diff --git a/.gitignore b/.gitignore index d35bbf7..ccd8331 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -.idea/ \ No newline at end of file +.idea/ +pool_configs/ \ No newline at end of file diff --git a/config.json b/config.json index a790452..a88de0e 100644 --- a/config.json +++ b/config.json @@ -2,15 +2,57 @@ "logLevel": "debug", "clustering": { "enabled": true, - "forks": "auto" + "forks": "1" }, "blockNotifyListener": { - "enabled": true, + "enabled": false, "port": 8117, "password": "test" }, - "website": { + + "redisBlockNotifyListener": { + "enabled" : false, + "redisPort" : 6379, + "redisHost" : "hostname", + "psubscribeKey" : "newblocks:*" + }, + "proxy": { "enabled": true, + "ports": { + "80": { + "diff": 32, + "varDiff": { + "minDiff" : 8, + "maxDiff" : 512, + "targetTime" : 15, + "retargetTime" : 90, + "variancePercent" : 30 + } + }, + "6000": { + "diff": 32, + "varDiff": { + "minDiff" : 8, + "maxDiff" : 512, + "targetTime" : 15, + "retargetTime" : 90, + "variancePercent" : 30 + } + }, + "8080": { + "diff": 32, + "varDiff": { + "minDiff" : 8, + "maxDiff" : 512, + "targetTime" : 15, + "retargetTime" : 90, + "variancePercent" : 30 + } + } + } + }, + "website": { + "enabled": false, "port": 80, "liveStats": true } diff --git a/init.js b/init.js index bbaefbc..07f8ea9 100644 --- a/init.js +++ b/init.js @@ -3,19 +3,18 @@ var os = require('os'); var cluster = require('cluster'); -var posix = require('posix'); -var PoolLogger = require('./libs/logUtil.js'); -var BlocknotifyListener = require('./libs/blocknotifyListener.js'); -var WorkerListener = require('./libs/workerListener.js'); -var PoolWorker = require('./libs/poolWorker.js'); -var PaymentProcessor = require('./libs/paymentProcessor.js'); -var Website = require('./libs/website.js'); - +var posix = require('posix'); +var PoolLogger = require('./libs/logUtil.js'); +var BlocknotifyListener = require('./libs/blocknotifyListener.js'); +var RedisBlocknotifyListener = require('./libs/redisblocknotifyListener.js'); +var WorkerListener = require('./libs/workerListener.js'); +var PoolWorker = require('./libs/poolWorker.js'); +var PaymentProcessor = require('./libs/paymentProcessor.js'); +var Website = require('./libs/website.js'); JSON.minify = JSON.minify || require("node-json-minify"); - var portalConfig = JSON.parse(JSON.minify(fs.readFileSync("config.json", {encoding: 'utf8'}))); - + var loggerInstance = new PoolLogger({ logLevel: portalConfig.logLevel @@ -37,7 +36,7 @@ catch(e){ if (cluster.isWorker){ - + switch(process.env.workerType){ case 'pool': new PoolWorker(loggerInstance); @@ -51,7 +50,18 @@ if (cluster.isWorker){ } return; -} +} /* else { + var coinNames = ['alphacoin','frankocoin','emerald','kittehcoin']; + var curIndex = 0; + setInterval(function () { + var newCoinName = coinNames[++curIndex % coinNames.length]; + console.log("SWITCHING to "+newCoinName); + var ipcMessage = {type:'switch', coin: newCoinName}; + Object.keys(cluster.workers).forEach(function(id) { + cluster.workers[id].send(ipcMessage); + }); + }, 20000); +} */ @@ -93,9 +103,10 @@ var spawnPoolWorkers = function(portalConfig, poolConfigs){ var createPoolWorker = function(forkId){ var worker = cluster.fork({ - workerType: 'pool', - forkId: forkId, - pools: serializedConfigs + workerType : 'pool', + forkId : forkId, + pools : serializedConfigs, + portalConfig : JSON.stringify(portalConfig), }); worker.on('exit', function(code, signal){ logError('poolWorker', 'system', 'Fork ' + forkId + ' died, spawning replacement worker...'); @@ -136,6 +147,21 @@ var startBlockListener = function(portalConfig){ listener.start(); }; +var startRedisBlockListener = function(portalConfig){ + //block notify options + //setup block notify here and use IPC to tell appropriate pools + var listener = new RedisBlocknotifyListener(portalConfig.redisBlockNotifyListener); + listener.on('log', function(text){ + logDebug('blocknotify', 'system', text); + }).on('hash', function (message) { + var ipcMessage = {type:'blocknotify', coin: message.coin, hash: message.hash}; + Object.keys(cluster.workers).forEach(function(id) { + cluster.workers[id].send(ipcMessage); + }); + }); + listener.start(); +}; + var startPaymentProcessor = function(poolConfigs){ var worker = cluster.fork({ @@ -152,6 +178,8 @@ var startPaymentProcessor = function(poolConfigs){ var startWebsite = function(portalConfig, poolConfigs){ + console.log(portalConfig.website); + if (!portalConfig.website.enabled) return; var worker = cluster.fork({ @@ -168,7 +196,6 @@ var startWebsite = function(portalConfig, poolConfigs){ }; - (function init(){ var poolConfigs = buildPoolConfigs(); @@ -179,8 +206,11 @@ var startWebsite = function(portalConfig, poolConfigs){ startBlockListener(portalConfig); + startRedisBlockListener(portalConfig); + startWorkerListener(poolConfigs); +; startWebsite(portalConfig, poolConfigs); -})(); \ No newline at end of file +})(); diff --git a/libs/logUtil.js b/libs/logUtil.js index 134d118..92d1cbe 100644 --- a/libs/logUtil.js +++ b/libs/logUtil.js @@ -53,12 +53,12 @@ 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/poolWorker.js b/libs/poolWorker.js index 3b00322..0b3c76f 100644 --- a/libs/poolWorker.js +++ b/libs/poolWorker.js @@ -1,4 +1,6 @@ var Stratum = require('stratum-pool'); +var Vardiff = require('stratum-pool/lib/varDiff.js'); +var net = require('net'); var MposCompatibility = require('./mposCompatibility.js'); var ShareProcessor = require('./shareProcessor.js'); @@ -6,11 +8,15 @@ var ShareProcessor = require('./shareProcessor.js'); module.exports = function(logger){ - var poolConfigs = JSON.parse(process.env.pools); - var forkId = process.env.forkId; + var poolConfigs = JSON.parse(process.env.pools); + var portalConfig = JSON.parse(process.env.portalConfig); - var pools = {}; + var forkId = process.env.forkId; + + var pools = {}; + var varDiffsInstances = {}; // contains all the vardiffs for the profit switching pool + var proxyStuff = {} //Handle messages from master process sent via IPC process.on('message', function(message) { switch(message.type){ @@ -18,6 +24,23 @@ module.exports = function(logger){ var pool = pools[message.coin.toLowerCase()] if (pool) pool.processBlockNotify(message.hash) break; + case 'switch': + var newCoinPool = pools[message.coin.toLowerCase()]; + if (newCoinPool) { + var oldPool = pools[proxyStuff.curActivePool]; + oldPool.relinquishMiners( + function (miner, cback) { + // relinquish miners that are attached to one of the "Auto-switch" ports and leave the others there. + cback(typeof(portalConfig.proxy.ports[miner.client.socket.localPort]) !== 'undefined') + }, + function (clients) { + newCoinPool.attachMiners(clients); + proxyStuff.curActivePool = message.coin.toLowerCase(); + } + ) + + } + break; } }); @@ -131,4 +154,36 @@ module.exports = function(logger){ pool.start(); pools[poolOptions.coin.name.toLowerCase()] = pool; }); + + + if (typeof(portalConfig.proxy) !== 'undefined' && portalConfig.proxy.enabled === true) { + proxyStuff.curActivePool = Object.keys(pools)[0]; + proxyStuff.proxys = {}; + proxyStuff.varDiffs = {}; + Object.keys(portalConfig.proxy.ports).forEach(function(port) { + proxyStuff.varDiffs[port] = new Vardiff(port, portalConfig.proxy.ports[port].varDiff); + }); + Object.keys(pools).forEach(function (coinName) { + var p = pools[coinName]; + Object.keys(proxyStuff.varDiffs).forEach(function(port) { + p.setVarDiff(port, proxyStuff.varDiffs[port]); + }); + }); + + Object.keys(portalConfig.proxy.ports).forEach(function (port) { + + proxyStuff.proxys[port] = net + .createServer({allowHalfOpen: true}, function(socket) { + console.log(proxyStuff.curActivePool); + pools[proxyStuff.curActivePool].getStratumServer().handleNewClient(socket); + } ) + .listen(parseInt(port), function(){ + console.log("Proxy listening on "+port); + }); + + }); + + + + } }; \ No newline at end of file diff --git a/libs/redisblocknotifyListener.js b/libs/redisblocknotifyListener.js new file mode 100644 index 0000000..05b9c7f --- /dev/null +++ b/libs/redisblocknotifyListener.js @@ -0,0 +1,36 @@ +var events = require('events'); +var redis = require('redis'); + +var listener = module.exports = function listener(options){ + + var _this = this; + var redisConnection; + + var emitLog = function(text){ + _this.emit('log', text); + }; + + + this.start = function(){ + redisConnection = redis.createClient(options.redisPort, options.redisHost); + redisConnection.on("pmessage", function (pattern, channel, message) { + var coinname = channel.split(':')[1]; + var blockhash = message; + //emitLog("Redis: Received block for "+coinname+" - hash: "+blockhash); + _this.emit('hash', { + "coin" : coinname, + "hash" : blockhash + }); + }); + redisConnection.on('connect', function (err, data) { + emitLog("Redis connected"); + }); + redisConnection.psubscribe(options.psubscribeKey); + emitLog("Connecting to redis!"); + } + + + +}; + +listener.prototype.__proto__ = events.EventEmitter.prototype; diff --git a/pool_configs/litecoin_testnet_example.json b/pool_configs/litecoin_testnet_example.json index 86ee96c..05ad29f 100644 --- a/pool_configs/litecoin_testnet_example.json +++ b/pool_configs/litecoin_testnet_example.json @@ -1,5 +1,5 @@ { - "disabled": false, + "disabled": true, "coin": "litecoin.json", "shareProcessing": {