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 2a2fdfd..b76bc54 100644 --- a/config.json +++ b/config.json @@ -1,11 +1,51 @@ { "clustering": { "enabled": true, - "forks": "auto" + "forks": "1" }, "blockNotifyListener": { - "enabled": true, + "enabled": false, "port": 8117, "password": "test" + }, + "redisBlockNotifyListener": { + "redisPort": 6379, + "redisHost": "coindaemons.ultimatecoinpool.com", + "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 + } + } + } } } \ No newline at end of file diff --git a/init.js b/init.js index 75619e4..7be2976 100644 --- a/init.js +++ b/init.js @@ -3,16 +3,17 @@ var os = require('os'); var cluster = require('cluster'); -var posix = require('posix'); -var PoolLogger = require('./libs/logutils.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 posix = require('posix'); +var PoolLogger = require('./libs/logutils.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'); JSON.minify = JSON.minify || require("node-json-minify"); - + var loggerInstance = new PoolLogger({ @@ -40,7 +41,7 @@ catch(e){ if (cluster.isWorker){ - + switch(process.env.workerType){ case 'pool': new PoolWorker(loggerInstance); @@ -51,6 +52,17 @@ 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); + }); + }, 120000); } @@ -93,9 +105,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...'); @@ -134,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({ @@ -147,7 +175,6 @@ var startPaymentProcessor = function(poolConfigs){ }; - (function init(){ var portalConfig = JSON.parse(JSON.minify(fs.readFileSync("config.json", {encoding: 'utf8'}))); @@ -159,6 +186,9 @@ var startPaymentProcessor = function(poolConfigs){ startBlockListener(portalConfig); + startRedisBlockListener(portalConfig); + startWorkerListener(poolConfigs); -})(); \ No newline at end of file + +})(); diff --git a/libs/logutils.js b/libs/logutils.js index 5ef890d..01054f5 100644 --- a/libs/logutils.js +++ b/libs/logutils.js @@ -63,7 +63,7 @@ var PoolLogger = function (configuration) { var desc = poolName ? '[' + poolName + '] ' : ''; console.log( '\u001b['+getSeverityColor(severity)+'m' + - dateFormat(new Date(), 'yyyy-mm-dd HH:mm:ss') + + dateFormat(new Date(), 'yyyy-mm-dd HH:MM:ss') + " ["+key+"]" + '\u001b[39m: ' + "\t" + desc + text); 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 2e9430c..f1f4cb1 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": {