From f57f3df054cbeb37750678a90aba783c3343e3a8 Mon Sep 17 00:00:00 2001 From: Interchained Date: Mon, 4 Jan 2021 14:18:52 -0500 Subject: [PATCH] Update blockUnlocker.js --- lib/blockUnlocker.js | 271 +++++++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 139 deletions(-) diff --git a/lib/blockUnlocker.js b/lib/blockUnlocker.js index e6673eb..0d537af 100644 --- a/lib/blockUnlocker.js +++ b/lib/blockUnlocker.js @@ -8,21 +8,21 @@ // Load required modules let async = require('async'); -let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api) -let notifications = require('./notifications.js') -let utils = require('./utils.js') +let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api); +let notifications = require('./notifications.js'); +let utils = require('./utils.js'); -let slushMiningEnabled = config.poolServer.slushMining && config.poolServer.slushMining.enabled +let slushMiningEnabled = config.poolServer.slushMining && config.poolServer.slushMining.enabled; // Initialize log system -let logSystem = 'unlocker' -require('./exceptionWriter.js')(logSystem) +let logSystem = 'unlocker'; +require('./exceptionWriter.js')(logSystem); /** * Run block unlocker **/ -log('info', logSystem, 'Started') +log('info', logSystem, 'Started'); function runInterval () { async.waterfall([ @@ -31,20 +31,19 @@ function runInterval () { function (callback) { redisClient.zrange(config.coin + ':blocks:candidates', 0, -1, 'WITHSCORES', function (error, results) { if (error) { - log('error', logSystem, 'Error trying to get pending blocks from redis %j', [error]) - callback(true) - return + log('error', logSystem, 'Error trying to get pending blocks from redis %j', [error]); + callback(true); + return; } if (results.length === 0) { - log('info', logSystem, 'No blocks candidates in redis') - callback(true) - return + log('info', logSystem, 'No blocks candidates in redis'); + callback(true); + return; } - let blocks = [] - + let blocks = []; for (let i = 0; i < results.length; i += 2) { - let parts = results[i].split(':') + let parts = results[i].split(':'); blocks.push({ serialized: results[i], height: parseInt(results[i + 1]), @@ -55,66 +54,63 @@ function runInterval () { difficulty: parts[4], shares: parts[5], score: parts.length >= 7 ? parts[6] : parts[5] - }) + }); } - - callback(null, blocks) + callback(null, blocks); }) }, // Check if blocks are orphaned function (blocks, callback) { async.filter(blocks, function (block, mapCback) { - let daemonType = config.daemonType ? config.daemonType.toLowerCase() : "default" - let blockHeight = ((daemonType === "forknote" || daemonType === "bytecoin") && config.blockUnlocker.fixBlockHeightRPC) ? block.height + 1 : block.height - let rpcMethod = config.blockUnlocker.useFirstVout ? 'getblock' : 'getblockheaderbyheight' + let daemonType = config.daemonType ? config.daemonType.toLowerCase() : "default"; + let blockHeight = ((daemonType === "forknote" || daemonType === "bytecoin") && config.blockUnlocker.fixBlockHeightRPC) ? block.height + 1 : block.height; + let rpcMethod = config.blockUnlocker.useFirstVout ? 'getblock' : 'getblockheaderbyheight'; apiInterfaces.rpcDaemon(rpcMethod, { height: blockHeight }, function (error, result) { if (error) { - log('error', logSystem, 'Error with %s RPC request for block %s - %j', [rpcMethod, block.serialized, error]) - block.unlocked = false - mapCback() - return + log('error', logSystem, 'Error with %s RPC request for block %s - %j', [rpcMethod, block.serialized, error]); + block.unlocked = false; + mapCback(); + return; } if (!result.block_header) { - log('error', logSystem, 'Error with getblockheaderbyheight RPC request for block %s - %j', [block.serialized, error]) - block.unlocked = false - mapCback() - return + log('error', logSystem, 'Error with getblockheaderbyheight RPC request for block %s - %j', [block.serialized, error]); + block.unlocked = false; + mapCback(); + return; } - let blockHeader = result.block_header - block.orphaned = blockHeader.hash === block.hash ? 0 : 1 - block.unlocked = blockHeader.depth >= config.blockUnlocker.depth - block.reward = blockHeader.reward + let blockHeader = result.block_header; + block.orphaned = blockHeader.hash === block.hash ? 0 : 1; + block.unlocked = blockHeader.depth >= config.blockUnlocker.depth; + block.reward = blockHeader.reward; if (config.blockUnlocker.useFirstVout) { - let vout = JSON.parse(result.json) - .miner_tx.vout + let vout = JSON.parse(result.json).miner_tx.vout; if (!vout.length) { - log('error', logSystem, 'Error: tx at height %s has no vouts!', [blockHeight]) - block.unlocked = false - mapCback() - return + log('error', logSystem, 'Error: tx at height %s has no vouts!', [blockHeight]); + block.unlocked = false; + mapCback(); + return; } - block.reward = vout[0].amount + block.reward = vout[0].amount; } else { - block.reward = blockHeader.reward + block.reward = blockHeader.reward; } if (config.blockUnlocker.networkFee) { - let networkFeePercent = config.blockUnlocker.networkFee / 100 - block.reward = block.reward - (block.reward * networkFeePercent) + let networkFeePercent = config.blockUnlocker.networkFee / 100; + block.reward = block.reward - (block.reward * networkFeePercent); } - mapCback(block.unlocked) + mapCback(block.unlocked); }) }, function (unlockedBlocks) { if (unlockedBlocks.length === 0) { - log('info', logSystem, 'No pending blocks are unlocked yet (%d pending)', [blocks.length]) - callback(true) - return + log('info', logSystem, 'No pending blocks are unlocked yet (%d pending)', [blocks.length]); + callback(true); + return; } - - callback(null, unlockedBlocks) + callback(null, unlockedBlocks); }) }, @@ -122,39 +118,40 @@ function runInterval () { function (blocks, callback) { let redisCommands = blocks.map(function (block) { - if (block.rewardType === 'prop') - return ['hgetall', config.coin + ':scores:prop:round' + block.height] - else - return ['hgetall', config.coin + ':scores:solo:round' + block.height] + if (block.rewardType === 'prop') { + return ['hgetall', config.coin + ':scores:prop:round' + block.height]; + } else { + return ['hgetall', config.coin + ':scores:solo:round' + block.height]; + } }) redisClient.multi(redisCommands) .exec(function (error, replies) { if (error) { - log('error', logSystem, 'Error with getting round shares from redis %j', [error]) - callback(true) - return + log('error', logSystem, 'Error with getting round shares from redis %j', [error]); + callback(true); + return; } for (let i = 0; i < replies.length; i++) { - let workerScores = replies[i] - blocks[i].workerScores = workerScores + let workerScores = replies[i]; + blocks[i].workerScores = workerScores; } - callback(null, blocks) + callback(null, blocks); }) }, // Handle orphaned blocks function (blocks, callback) { - let orphanCommands = [] - + let orphanCommands = []; blocks.forEach(function (block) { - if (!block.orphaned) return - - orphanCommands.push(['del', config.coin + ':scores:solo:round' + block.height]) - orphanCommands.push(['del', config.coin + ':scores:prop:round' + block.height]) - orphanCommands.push(['del', config.coin + ':shares_actual:solo:round' + block.height]) - orphanCommands.push(['del', config.coin + ':shares_actual:prop:round' + block.height]) - orphanCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]) + if (!block.orphaned) { + return; + } + orphanCommands.push(['del', config.coin + ':scores:solo:round' + block.height]); + orphanCommands.push(['del', config.coin + ':scores:prop:round' + block.height]); + orphanCommands.push(['del', config.coin + ':shares_actual:solo:round' + block.height]); + orphanCommands.push(['del', config.coin + ':shares_actual:prop:round' + block.height]); + orphanCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]); orphanCommands.push(['zadd', config.coin + ':blocks:matured', block.height, [ block.rewardType, block.login, @@ -163,13 +160,12 @@ function runInterval () { block.difficulty, block.shares, block.orphaned - ].join(':')]) + ].join(':')]); if (block.workerScores && !slushMiningEnabled) { - let workerScores = block.workerScores - Object.keys(workerScores) - .forEach(function (worker) { - orphanCommands.push(['hincrby', config.coin + ':scores:roundCurrent', worker, workerScores[worker]]) + let workerScores = block.workerScores; + Object.keys(workerScores).forEach(function (worker) { + orphanCommands.push(['hincrby', config.coin + ':scores:roundCurrent', worker, workerScores[worker]]); }) } @@ -184,34 +180,35 @@ function runInterval () { }) if (orphanCommands.length > 0) { - redisClient.multi(orphanCommands) - .exec(function (error, replies) { + redisClient.multi(orphanCommands).exec(function (error, replies) { if (error) { - log('error', logSystem, 'Error with cleaning up data in redis for orphan block(s) %j', [error]) - callback(true) - return + log('error', logSystem, 'Error with cleaning up data in redis for orphan block(s) %j', [error]); + callback(true); + return; } - callback(null, blocks) + callback(null, blocks); }) } else { - callback(null, blocks) + callback(null, blocks); } }, // Handle unlocked blocks function (blocks, callback) { - let unlockedBlocksCommands = [] - let payments = {} - let totalBlocksUnlocked = 0 + let unlockedBlocksCommands = []; + let payments = {}; + let totalBlocksUnlocked = 0; blocks.forEach(function (block) { - if (block.orphaned) return - totalBlocksUnlocked++ + if (block.orphaned) { + return; + } + totalBlocksUnlocked++; - unlockedBlocksCommands.push(['del', config.coin + ':scores:solo:round' + block.height]) - unlockedBlocksCommands.push(['del', config.coin + ':scores:prop:round' + block.height]) - unlockedBlocksCommands.push(['del', config.coin + ':shares_actual:solo:round' + block.height]) - unlockedBlocksCommands.push(['del', config.coin + ':shares_actual:prop:round' + block.height]) - unlockedBlocksCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]) + unlockedBlocksCommands.push(['del', config.coin + ':scores:solo:round' + block.height]); + unlockedBlocksCommands.push(['del', config.coin + ':scores:prop:round' + block.height]); + unlockedBlocksCommands.push(['del', config.coin + ':shares_actual:solo:round' + block.height]); + unlockedBlocksCommands.push(['del', config.coin + ':shares_actual:prop:round' + block.height]); + unlockedBlocksCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]); unlockedBlocksCommands.push(['zadd', config.coin + ':blocks:matured', block.height, [ block.rewardType, block.login, @@ -221,50 +218,47 @@ function runInterval () { block.shares, block.orphaned, block.reward - ].join(':')]) + ].join(':')]); - let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100 - if (block.rewardType === 'solo') - feePercent = (config.blockUnlocker.soloFee >= 0 ? config.blockUnlocker.soloFee : (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0)) / 100 - - if (Object.keys(donations) - .length) { + let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100; + if (block.rewardType === 'solo') { + feePercent = (config.blockUnlocker.soloFee >= 0 ? config.blockUnlocker.soloFee : (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0)) / 100; + } + if (Object.keys(donations).length) { for (let wallet in donations) { - let percent = donations[wallet] / 100 - feePercent += percent - payments[wallet] = Math.round(block.reward * percent) - log('info', logSystem, 'Block %d donation to %s as %d percent of reward: %d', [block.height, wallet, percent, payments[wallet]]) + let percent = donations[wallet] / 100; + feePercent += percent; + payments[wallet] = Math.round(block.reward * percent); + log('info', logSystem, 'Block %d donation to %s as %d percent of reward: %d', [block.height, wallet, percent, payments[wallet]]); } } - let reward = 0 - let finderReward = 0 - + let reward = 0; + let finderReward = 0; if (block.rewardType === 'solo') { - reward = Math.round(block.reward - (block.reward * feePercent)) - log('info', logSystem, 'Unlocked SOLO block %d with reward %d and donation fee %d. Miners reward: %d', [block.height, block.reward, feePercent, reward]) + reward = Math.round(block.reward - (block.reward * feePercent)); + log('info', logSystem, 'Unlocked SOLO block %d with reward %d and donation fee %d. Miners reward: %d', [block.height, block.reward, feePercent, reward]); } else { - let finderPercent = (config.blockUnlocker.finderReward > 0 ? config.blockUnlocker.finderReward : 0) / 100 - finderReward = Math.round(block.reward * finderPercent) - reward = Math.round(block.reward - (block.reward * (feePercent + finderPercent))) - log('info', logSystem, 'Unlocked PROP block %d with reward %d, finders fee %d, and donation fee %d. Miners reward: %d Finders Reward: %d', [block.height, block.reward, finderPercent, feePercent, reward, finderReward]) + let finderPercent = (config.blockUnlocker.finderReward > 0 ? config.blockUnlocker.finderReward : 0) / 100; + finderReward = Math.round(block.reward * finderPercent); + reward = Math.round(block.reward - (block.reward * (feePercent + finderPercent))); + log('info', logSystem, 'Unlocked PROP block %d with reward %d, finders fee %d, and donation fee %d. Miners reward: %d Finders Reward: %d', [block.height, block.reward, finderPercent, feePercent, reward, finderReward]); } if (block.workerScores) { - let totalScore = parseFloat(block.score) + let totalScore = parseFloat(block.score); //deal with solo block if (block.rewardType === 'solo') { - let worker = block.login - payments[worker] = (payments[worker] || 0) + reward - log('info', logSystem, 'SOLO Block %d payment to %s for %d%% of total block score: %d', [block.height, worker, 100, payments[worker]]) + let worker = block.login; + payments[worker] = (payments[worker] || 0) + reward; + log('info', logSystem, 'SOLO Block %d payment to %s for %d%% of total block score: %d', [block.height, worker, 100, payments[worker]]); } else { - Object.keys(block.workerScores) - .forEach(function (worker) { - let percent = block.workerScores[worker] / totalScore - let workerReward = Math.round(reward * percent) - payments[worker] = block.login === worker ? (payments[worker] || 0) + (workerReward + finderReward) : (payments[worker] || 0) + workerReward - log('info', logSystem, 'PROP Block %d payment to %s for %d%% of total block score: %d', [block.height, worker, percent * 100, payments[worker]]) - }) + Object.keys(block.workerScores).forEach(function (worker) { + let percent = block.workerScores[worker] / totalScore; + let workerReward = Math.round(reward * percent); + payments[worker] = block.login === worker ? (payments[worker] || 0) + (workerReward + finderReward) : (payments[worker] || 0) + workerReward; + log('info', logSystem, 'PROP Block %d payment to %s for %d%% of total block score: %d', [block.height, worker, percent * 100, payments[worker]]); + }); } } @@ -276,40 +270,39 @@ function runInterval () { 'DIFFICULTY': block.difficulty, 'SHARES': block.shares, 'EFFORT': Math.round(block.shares / block.difficulty * 100) + '%' - }) + }); }) for (let worker in payments) { - let amount = parseInt(payments[worker]) + let amount = parseInt(payments[worker]); if (amount <= 0) { - delete payments[worker] - continue + delete payments[worker]; + continue; } - unlockedBlocksCommands.push(['hincrby', `${config.coin}:workers:${worker}`, 'balance', amount]) + unlockedBlocksCommands.push(['hincrby', `${config.coin}:workers:${worker}`, 'balance', amount]); } if (unlockedBlocksCommands.length === 0) { - log('info', logSystem, 'No unlocked blocks yet (%d pending)', [blocks.length]) - callback(true) - return + log('info', logSystem, 'No unlocked blocks yet (%d pending)', [blocks.length]); + callback(true); + return; } redisClient.multi(unlockedBlocksCommands) .exec(function (error, replies) { if (error) { - log('error', logSystem, 'Error with unlocking blocks %j', [error]) - callback(true) - return + log('error', logSystem, 'Error with unlocking blocks %j', [error]); + callback(true); + return; } - log('info', logSystem, 'Unlocked %d blocks and update balances for %d workers', [totalBlocksUnlocked, Object.keys(payments) - .length - ]) - callback(null) + log('info', logSystem, 'Unlocked %d blocks and update balances for %d workers', [totalBlocksUnlocked, Object.keys(payments).length + ]); + callback(null); }) } ], function (error, result) { - setTimeout(runInterval, config.blockUnlocker.interval * 1000) + setTimeout(runInterval, config.blockUnlocker.interval * 1000); }) } -runInterval() +runInterval();