diff --git a/README.md b/README.md index 27b32e4..ea160d6 100644 --- a/README.md +++ b/README.md @@ -313,11 +313,11 @@ For more information on these configuration options see the [pool module documen 1. In `config.json` set the port and password for `blockNotifyListener` 2. In your daemon conf file set the `blocknotify` command to use: ``` -[path to scripts/blockNotify.js] [listener host]:[listener port] [listener password] [coin name in config] %s +node [path to scripts/blockNotify.js] [listener host]:[listener port] [listener password] [coin name in config] %s ``` Example: inside `dogecoin.conf` add the line ``` -blocknotify="scripts/blockNotify.js localhost:8117 mySuperSecurePassword dogecoin %s" +blocknotify="node scripts/blockNotify.js localhost:8117 mySuperSecurePassword dogecoin %s" ``` @@ -344,6 +344,14 @@ To support development of this project feel free to donate :) BTC: 1KRotMnQpxu3sePQnsVLRy3EraRFYfJQFR + +Credits +------- +* [vekexasia](https://github.com/vekexasia) - co-developer & great tester +* [TheSeven](https://github.com/TheSeven) - answering an absurd amount of my questions and being a very helpful and king gentleman +* Those that contributed to [node-stratum](/zone117x/node-stratum) + + License ------- Released under the GNU General Public License v2 diff --git a/config.json b/config.json index a88de0e..2baa2eb 100644 --- a/config.json +++ b/config.json @@ -2,7 +2,7 @@ "logLevel": "debug", "clustering": { "enabled": true, - "forks": "1" + "forks": "auto" }, "blockNotifyListener": { "enabled": false, @@ -16,8 +16,13 @@ "redisHost" : "hostname", "psubscribeKey" : "newblocks:*" }, + "website": { + "enabled": false, + "port": 80, + "statUpdateInterval": 3 + }, "proxy": { - "enabled": true, + "enabled": false, "ports": { "80": { "diff": 32, @@ -50,10 +55,5 @@ } } } - }, - "website": { - "enabled": false, - "port": 80, - "liveStats": true } } \ No newline at end of file diff --git a/init.js b/init.js index 07f8ea9..09c66b2 100644 --- a/init.js +++ b/init.js @@ -150,6 +150,9 @@ var startBlockListener = function(portalConfig){ var startRedisBlockListener = function(portalConfig){ //block notify options //setup block notify here and use IPC to tell appropriate pools + + if (!portalConfig.redisBlockNotifyListener.enabled) return; + var listener = new RedisBlocknotifyListener(portalConfig.redisBlockNotifyListener); listener.on('log', function(text){ logDebug('blocknotify', 'system', text); @@ -178,7 +181,6 @@ var startPaymentProcessor = function(poolConfigs){ var startWebsite = function(portalConfig, poolConfigs){ - console.log(portalConfig.website); if (!portalConfig.website.enabled) return; @@ -209,7 +211,6 @@ var startWebsite = function(portalConfig, poolConfigs){ startRedisBlockListener(portalConfig); startWorkerListener(poolConfigs); -; startWebsite(portalConfig, poolConfigs); diff --git a/libs/api.js b/libs/api.js index 53ec46c..7dc8bab 100644 --- a/libs/api.js +++ b/libs/api.js @@ -40,8 +40,20 @@ module.exports = function(logger, poolConfigs){ setInterval(clearExpiredHashrates, 10 * 60 * 1000); clearExpiredHashrates(); + + + + this.getStats = function(callback){ + + /* + { global: { + + } + + */ + //get stats like hashrate and in/valid shares/blocks and workers in current round }; diff --git a/libs/logUtil.js b/libs/logUtil.js index 92d1cbe..06803a6 100644 --- a/libs/logUtil.js +++ b/libs/logUtil.js @@ -53,11 +53,11 @@ var PoolLogger = function (configuration) { var desc = poolName ? '[' + poolName + '] ' : ''; console.log( - '\u001b['+getSeverityColor(severity)+'m' + - dateFormat(new Date(), 'yyyy-mm-dd HH:MM:ss') + - " ["+key+"]" + '\u001b[39m: ' + "\t" + - desc + - text); + '\u001b[' + getSeverityColor(severity) + 'm' + + dateFormat(new Date(), 'yyyy-mm-dd HH:MM:ss') + + " [" + key + "]" + '\u001b[39m: ' + "\t" + + desc + text + ); } // public diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index b9b9d6e..2ed33ab 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -79,6 +79,48 @@ function SetupForPool(logger, poolOptions){ connectToRedis(); + /* When blocks or orphaned, all shares contributed to that round would receive no reward. That doesn't seem fair + so we still all the shares from an orphaned rounds into the current round. + */ + var adoptOrphanRounds = function(rounds){ + + var shareLookups = rounds.map(function(r){ + return ['hgetall', coin + '_shares:round' + r.height] + }); + + var shareIncries = []; + + + + redisClient.multi(shareLookups).exec(function(error, allWorkerShares){ + if (error){ + paymentLogger.error('redis', 'Error with multi get rounds share for adopting orphan'); + return; + } + + var workerRewards = {}; + + + for (var i = 0; i < rounds.length; i++){ + var round = rounds[i]; + var workerShares = allWorkerShares[i]; + + var reward = round.reward * (1 - processingConfig.feePercent); + + var totalShares = Object.keys(workerShares).reduce(function(p, c){ + return p + parseInt(workerShares[c]) + }, 0); + + + for (var worker in workerShares){ + var percent = parseInt(workerShares[worker]) / totalShares; + var workerRewardTotal = Math.floor(reward * percent); + if (!(worker in workerRewards)) workerRewards[worker] = 0; + workerRewards[worker] += workerRewardTotal; + } + } + }); + }; var processPayments = function(){ @@ -125,29 +167,61 @@ function SetupForPool(logger, poolOptions){ return; } + + for (var i = txDetails.length; i > 0; --i){ + var tx = txDetails[i]; + if (tx.error || !tx.result){ + console.log('error with requesting transaction from block daemon: ' + JSON.stringify(t)); + txDetails.splice(i, 1); + } + } + + + var orphanedRounds = []; + var confirmedRounds = []; //Rounds that are not confirmed yet are removed from the round array //We also get reward amount for each block from daemon reply - rounds = rounds.filter(function(r){ - var tx = txDetails.filter(function(t){ return t.result.txid === r.txHash; })[0]; - if (tx.result.details[0].category !== 'generate') return false; - r.amount = tx.result.amount; - r.magnitude = r.reward / r.amount; - return true; + rounds.forEach(function(r){ + + var tx = txDetails.filter(function(tx){return tx.result.txid === r.txHash})[0]; + + if (!tx){ + console.log('daemon did not give us back a transaction that we asked for: ' + r.txHash); + return; + } + + + r.category = tx.result.details[0].category; + + if (r.category === 'orphan'){ + orphanedRounds.push(r); + + } + else if (r.category === 'generate'){ + r.amount = tx.result.amount; + r.magnitude = r.reward / r.amount; + confirmedRounds.push(r); + } + }); - if (rounds.length === 0){ - callback('done - no confirmed transactions yet'); - return; + if (orphanedRounds.length === 0 && confirmedRounds.length === 0){ + callback('done - no confirmed or orhpaned rounds'); + } + else{ + callback(null, confirmedRounds, orphanedRounds); } - callback(null, rounds); - }); }, /* Does a batch redis call to get shares contributed to each round. Then calculates the reward amount owned to each miner for each round. */ - function(rounds, callback){ + function(confirmedRounds, orphanedRounds, callback){ + + var rounds = []; + for (var i = 0; i < orphanedRounds; i++) rounds.push(orphanedRounds[i]); + for (var i = 0; i < confirmedRounds; i++) rounds.push(confirmedRounds[i]); var shareLookups = rounds.map(function(r){ @@ -160,6 +234,16 @@ function SetupForPool(logger, poolOptions){ return; } + var orphanMergeCommands = [] + for (var i = 0; i < orphanedRounds.length; i++){ + var workerShares = allWorkerShares[i]; + Object.keys(workerShares).forEach(function(worker){ + orphanMergeCommands.push(['hincrby', coin + '_shares:roundCurrent', worker, workerShares[worker]]); + }); + orphanMergeCommands.push([]); + } + + var workerRewards = {}; diff --git a/libs/poolWorker.js b/libs/poolWorker.js index 0b3c76f..de9ee51 100644 --- a/libs/poolWorker.js +++ b/libs/poolWorker.js @@ -94,10 +94,9 @@ module.exports = function(logger){ var shareProcessor = new ShareProcessor(poolLogger, poolOptions) handlers.auth = function(workerName, password, authCallback){ - authCallback({ - error: null, - authorized: true, - disconnect: false + pool.daemon.cmd('validateaddress', [workerName], function(results){ + var isValid = results.filter(function(r){return r.response.isvalid}).length > 0; + authCallback(isValid); }); }; diff --git a/libs/shareProcessor.js b/libs/shareProcessor.js index 6b9844c..e5830e3 100644 --- a/libs/shareProcessor.js +++ b/libs/shareProcessor.js @@ -74,10 +74,7 @@ module.exports = function(logger, poolConfig){ connection.multi(redisCommands).exec(function(err, replies){ if (err) - console.log('error with share processor multi ' + JSON.stringify(err)); - else{ - console.log(JSON.stringify(replies)); - } + logger.error('redis', 'error with share processor multi ' + JSON.stringify(err)); }); diff --git a/pool_configs/litecoin_testnet_example.json b/pool_configs/litecoin_testnet_example.json index 05ad29f..3ff4fbe 100644 --- a/pool_configs/litecoin_testnet_example.json +++ b/pool_configs/litecoin_testnet_example.json @@ -1,5 +1,5 @@ { - "disabled": true, + "disabled": false, "coin": "litecoin.json", "shareProcessing": { @@ -48,8 +48,8 @@ }, "ports": { - "3032": { - "diff": 32, + "3008":{ + "diff": 8, "varDiff": { "minDiff": 8, "maxDiff": 512, @@ -58,6 +58,9 @@ "variancePercent": 30 } }, + "3032": { + "diff": 32 + }, "3256": { "diff": 256 } diff --git a/scripts/blockNotify.js b/scripts/blockNotify.js index ae328b8..ea61d2c 100644 --- a/scripts/blockNotify.js +++ b/scripts/blockNotify.js @@ -1,13 +1,10 @@ -#!/usr/bin/env node -/** - * This script should be hooked to the coin daemon as follow: - * - * litecoind -blocknotify="/path/to/this/script/blockNotify.js localhost:8117 password litecoin %s" - * - * The above will send tell litecoin to launch this script with those parameters every time - * a block is found. - * This script will then send the blockhash along with other informations to a listening tcp socket -**/ + +/* +This script should be hooked to the coin daemon as follow: +litecoind -blocknotify="node /path/to/this/script/blockNotify.js localhost:8117 password litecoin %s" +The above will send tell litecoin to launch this script with those parameters every time a block is found. +This script will then send the blockhash along with other information to a listening tcp socket +*/ var net = require('net'); var config = process.argv[1]; diff --git a/statsExampleJson.js b/statsExampleJson.js new file mode 100644 index 0000000..5c7e28d --- /dev/null +++ b/statsExampleJson.js @@ -0,0 +1,33 @@ +var stats = { + + global:{ + hashrate: 1000, //in KH/s + validShares: 1, + invalidShares: 1, + validBlocks: 1, + invalidBlocks: 1, + blocksPending: 1, + blocksConfirmed: 1, + blocksOrphaned: 1, + connectedMiners: 344 + }, + pools:[ + { + coin: "Dogecoin", + sybmol: 'doge', + stats:{ + hashrate: 1000, //in KH/s + validShares: 1, + invalidShares: 1, + validBlocks: 1, + invalidBlocks: 1, + blocksPending: 1, + blocksConfirmed: 1, + blocksOrphaned: 1, + connectedMiners: 34545, + totalPayedOut: 3343.789797 + } + } + ] + +} \ No newline at end of file