diff --git a/coins/copperbars.json b/coins/copperbars.json new file mode 100644 index 0000000..597043d --- /dev/null +++ b/coins/copperbars.json @@ -0,0 +1,7 @@ +{ + "name": "Copperbars", + "symbol": "CPR", + "algorithm": "scrypt-jane", + "chainStartTime": 1376184687, + "txMessages": false +} \ No newline at end of file diff --git a/init.js b/init.js index dcd7b6b..c2cdebf 100644 --- a/init.js +++ b/init.js @@ -143,7 +143,7 @@ var spawnPoolWorkers = function(portalConfig, poolConfigs){ i++; if (i === numForks){ clearInterval(spawnInterval); - logger.debug('Master', 'PoolSpawner', 'Spawned pools for all ' + numForks + ' configured forks'); + logger.debug('Master', 'PoolSpawner', 'Spawned ' + Object.keys(poolConfigs).length + ' pool(s) on ' + numForks + ' thread(s)'); } }, 250); diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 2f2f25c..70b80aa 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -9,70 +9,120 @@ module.exports = function(logger){ var poolConfigs = JSON.parse(process.env.pools); + var enabledPools = []; Object.keys(poolConfigs).forEach(function(coin) { - SetupForPool(logger, poolConfigs[coin]); + var poolOptions = poolConfigs[coin]; + if (poolOptions.shareProcessing && + poolOptions.shareProcessing.internal && + poolOptions.shareProcessing.internal.enabled) + enabledPools.push(coin); }); + async.filter(enabledPools, function(coin, callback){ + SetupForPool(logger, poolConfigs[coin], function(setupResults){ + callback(setupResults); + }); + }, function(coins){ + coins.forEach(function(coin){ + + var poolOptions = poolConfigs[coin]; + var processingConfig = poolOptions.shareProcessing.internal; + var logSystem = 'Payments'; + var logComponent = coin; + + logger.debug(logSystem, logComponent, 'Payment processing setup to run every ' + + processingConfig.paymentInterval + ' second(s) with daemon (' + + processingConfig.daemon.user + '@' + processingConfig.daemon.host + ':' + processingConfig.daemon.port + + ') and redis (' + processingConfig.redis.host + ':' + processingConfig.redis.port + ')'); + + }); + }); + + }; -function SetupForPool(logger, poolOptions){ - - if (!poolOptions.shareProcessing || - !poolOptions.shareProcessing.internal || - !poolOptions.shareProcessing.internal.enabled) - return; +function SetupForPool(logger, poolOptions, setupFinished){ var coin = poolOptions.coin.name; var processingConfig = poolOptions.shareProcessing.internal; - - var logSystem = 'Payments'; var logComponent = coin; - var daemon = new Stratum.daemon.interface([processingConfig.daemon]); - daemon.once('online', function(){ - logger.debug(logSystem, logComponent, 'Connected to daemon for payment processing'); - - daemon.cmd('validateaddress', [poolOptions.address], function(result){ - if (!result[0].response || !result[0].response.ismine){ - logger.error(logSystem, logComponent, - 'Daemon does not own pool address - payment processing can not be done with this daemon'); - } - }); - }).once('connectionFailed', function(error){ - logger.error(logSystem, logComponent, 'Failed to connect to daemon for payment processing: ' + - JSON.stringify(error)); - }).on('error', function(error){ - logger.error(logSystem, logComponent, 'Daemon error ' + JSON.stringify(error)); - }).init(); - - - + var daemon; var redisClient; + async.parallel([ + + function(callback){ + daemon = new Stratum.daemon.interface([processingConfig.daemon]); + daemon.once('online', function(){ + daemon.cmd('validateaddress', [poolOptions.address], function(result){ + if (!result[0].response || !result[0].response.ismine){ + logger.error(logSystem, logComponent, + 'Daemon does not own pool address - payment processing can not be done with this daemon'); + return; + } + callback() + }); + }).once('connectionFailed', function(error){ + logger.error(logSystem, logComponent, 'Failed to connect to daemon for payment processing: config ' + + JSON.stringify(processingConfig.daemon) + ', error: ' + + JSON.stringify(error)); + callback('Error connecting to deamon'); + }).on('error', function(error){ + logger.error(logSystem, logComponent, 'Daemon error ' + JSON.stringify(error)); + }).init(); + }, + function(callback){ + + redisClient = redis.createClient(processingConfig.redis.port, processingConfig.redis.host); + redisClient.on('ready', function(){ + if (callback) { + callback(); + callback = null; + return; + } + logger.debug(logSystem, logComponent, 'Connected to redis at ' + + processingConfig.redis.host + ':' + processingConfig.redis.port + ' for payment processing'); + }).on('end', function(){ + logger.error(logSystem, logComponent, 'Connection to redis database as been ended'); + }).once('error', function(){ + if (callback) { + logger.error(logSystem, logComponent, 'Failed to connect to redis at ' + + processingConfig.redis.host + ':' + processingConfig.redis.port + ' for payment processing'); + callback('Error connecting to redis'); + callback = null; + } + }); + + } + ], function(err){ + if (err){ + setupFinished(false); + return; + } + setInterval(function(){ + try { + processPayments(); + } catch(e){ + throw e; + } + }, processingConfig.paymentInterval * 1000); + setTimeout(processPayments, 100); + setupFinished(true); + }); + + + + + + - var connectToRedis = function(){ - var reconnectTimeout; - redisClient = redis.createClient(processingConfig.redis.port, processingConfig.redis.host); - redisClient.on('ready', function(){ - clearTimeout(reconnectTimeout); - logger.debug(logSystem, logComponent, 'Successfully connected to redis database'); - })/*).on('error', function(err){ - logger.error(logSystem, logComponent, 'Redis client had an error: ' + JSON.stringify(err)) - })*/.on('end', function(){ - logger.error(logSystem, logComponent, 'Connection to redis database as been ended'); - logger.warning(logSystem, logComponent, 'Trying reconnection to redis in 3 seconds...'); - reconnectTimeout = setTimeout(function(){ - connectToRedis(); - }, 3000); - }); - }; - connectToRedis(); /* Number.toFixed gives us the decimal places we want, but as a string. parseFloat turns it back into number @@ -124,30 +174,6 @@ function SetupForPool(logger, poolOptions){ }); }, - /* First get data from all pending blocks via batch RPC call, we need the coinbase txHash. */ - /*(function(rounds, callback){ - var batchRPCcommand = rounds.map(function(r){ - return ['getblock', [r.solution]]; - }); - - daemon.batchCmd(batchRPCcommand, function(error, blocks) { - - if (error || !blocks) { - callback('Check finished - daemon rpc error with batch gettransactions ' + - JSON.stringify(error)); - return; - } - blocks.forEach(function (b, i) { - if (b.error || b.result.hash !== rounds[i].solution){ - logger.error(logSystem, logComponent, "Did daemon drop a block? " + rounds[i].solution); - return; - } - rounds[i].txHash = b.result.tx[0]; - }); - callback(null, rounds); - }); - },*/ - /* Does a batch rpc call to daemon with all the transaction hashes to see if they are confirmed yet. It also adds the block reward amount to the round object - which the daemon gives also gives us. */ function(rounds, callback){ @@ -535,7 +561,7 @@ function SetupForPool(logger, poolOptions){ var paymentProcessTime = Date.now() - startPaymentProcess; if (error) - logger.debug(logSystem, logComponent, '[' + paymentProcessTime + 'ms] ' + error); + logger.debug(logSystem, logComponent, '[Took ' + paymentProcessTime + 'ms] ' + error); else{ logger.debug(logSystem, logComponent, '[' + paymentProcessTime + 'ms] ' + result); @@ -579,14 +605,4 @@ function SetupForPool(logger, poolOptions){ }; - - setInterval(function(){ - try { - processPayments(); - } catch(e){ - throw e; - } - }, processingConfig.paymentInterval * 1000); - setTimeout(processPayments, 100); - }; \ No newline at end of file diff --git a/libs/poolWorker.js b/libs/poolWorker.js index 8706fe8..fdcde2f 100644 --- a/libs/poolWorker.js +++ b/libs/poolWorker.js @@ -13,11 +13,12 @@ module.exports = function(logger){ var poolConfigs = JSON.parse(process.env.pools); var portalConfig = JSON.parse(process.env.portalConfig); - var forkId = process.env.forkId; + var forkId = process.env.forkId; - var pools = {}; + var pools = {}; + + var proxyStuff = {}; - var proxyStuff = {} //Handle messages from master process sent via IPC process.on('message', function(message) { switch(message.type){ @@ -52,7 +53,7 @@ module.exports = function(logger){ var logSystem = 'Pool'; var logComponent = coin; - var logSubCat = 'Fork ' + forkId; + var logSubCat = 'Thread ' + (parseInt(forkId) + 1); var handlers = { diff --git a/libs/shareProcessor.js b/libs/shareProcessor.js index 56229a2..938bd48 100644 --- a/libs/shareProcessor.js +++ b/libs/shareProcessor.js @@ -20,31 +20,23 @@ module.exports = function(logger, poolConfig){ var redisConfig = internalConfig.redis; var coin = poolConfig.coin.name; - var logSystem = 'Shares'; + var forkId = process.env.forkId; + var logSystem = 'Pool'; + var logComponent = coin; + var logSubCat = 'Thread ' + (parseInt(forkId) + 1); - var connection; + var connection = redis.createClient(redisConfig.port, redisConfig.host); - function connect(){ - - var reconnectTimeout; - - connection = redis.createClient(redisConfig.port, redisConfig.host); - connection.on('ready', function(){ - clearTimeout(reconnectTimeout); - logger.debug(logSystem, 'redis', 'Successfully connected to redis database'); - }); - connection.on('error', function(err){ - logger.error(logSystem, 'redis', 'Redis client had an error: ' + JSON.stringify(err)) - }); - connection.on('end', function(){ - logger.error(logSystem, 'redis', 'Connection to redis database as been ended'); - logger.warning(logSystem, 'redis', 'Trying reconnection in 3 seconds...'); - reconnectTimeout = setTimeout(function(){ - connect(); - }, 3000); - }); - } - connect(); + connection.on('ready', function(){ + logger.debug(logSystem, logComponent, logSubCat, 'Share processing setup with redis (' + redisConfig.host + + ':' + redisConfig.port + ')'); + }); + connection.on('error', function(err){ + logger.error(logSystem, logComponent, logSubCat, 'Redis client had an error: ' + JSON.stringify(err)) + }); + connection.on('end', function(){ + logger.error(logSystem, logComponent, logSubCat, 'Connection to redis database as been ended'); + }); @@ -78,9 +70,9 @@ module.exports = function(logger, poolConfig){ connection.multi(redisCommands).exec(function(err, replies){ if (err) - logger.error(logSystem, 'redis', 'Error with share processor multi ' + JSON.stringify(err)); + logger.error(logSystem, logComponent, logSubCat, 'Error with share processor multi ' + JSON.stringify(err)); else - logger.debug(logSystem, 'redis', 'Share data and stats recorded'); + logger.debug(logSystem, logComponent, logSubCat, 'Share data and stats recorded'); }); diff --git a/libs/stats.js b/libs/stats.js index 8e00f58..9977256 100644 --- a/libs/stats.js +++ b/libs/stats.js @@ -140,12 +140,11 @@ module.exports = function(logger, portalConfig, poolConfigs){ }); var shareMultiplier = algos[coinStats.algorithm].multiplier || 0; var hashratePre = shareMultiplier * coinStats.shares / portalConfig.website.hashrateWindow; - console.log([hashratePre, shareMultiplier, coinStats.shares, portalConfig.website.hashrateWindow]); coinStats.hashrate = hashratePre / 1e3 | 0; portalStats.global.hashrate += coinStats.hashrate; portalStats.global.workers += Object.keys(coinStats.workers).length; - coinStats.hashrates; - coinStats.shares; + delete coinStats.hashrates; + delete coinStats.shares; }); _this.stats = portalStats; diff --git a/pool_configs/bitcoin_example.json b/pool_configs/bitcoin_example.json new file mode 100644 index 0000000..fb92dcd --- /dev/null +++ b/pool_configs/bitcoin_example.json @@ -0,0 +1,64 @@ +{ + "enabled": false, + "coin": "bitcoin.json", + + "shareProcessing": { + "internal": { + "enabled": true, + "validateWorkerAddress": true, + "paymentInterval": 60, + "minimumPayment": 100.001, + "minimumReserve": 10, + "feePercent": 0.02, + "feeReceiveAddress": "msjLr1XfpB6aAL1wi8e2CDnDSNhF4WrJ5n", + "feeWithdrawalThreshold": 5, + "daemon": { + "host": "localhost", + "port": 18332, + "user": "testuser", + "password": "testpass" + }, + "redis": { + "host": "localhost", + "port": 6379 + } + }, + "mpos": { + "enabled": false, + "host": "localhost", + "port": 3306, + "user": "me", + "password": "mypass", + "database": "ltc", + "stratumAuth": "password" + } + }, + + "address": "mtCiLWzBy9EpuxzkLwizPYiPFDy69HTd4b", + "blockRefreshInterval": 1000, + "txRefreshInterval": 20000, + "connectionTimeout": 600, + + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 + }, + + "ports": { + "6774": { + "diff": 1 + } + }, + + "daemons": [ + { + "host": "localhost", + "port": 18332, + "user": "testuser", + "password": "testpass" + } + ] +} \ No newline at end of file diff --git a/pool_configs/darkcoin_example.json b/pool_configs/darkcoin_example.json index 7b8487a..7f8fda4 100644 --- a/pool_configs/darkcoin_example.json +++ b/pool_configs/darkcoin_example.json @@ -6,7 +6,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, diff --git a/pool_configs/galleon_example.json b/pool_configs/galleon_example.json index e149565..3506975 100644 --- a/pool_configs/galleon_example.json +++ b/pool_configs/galleon_example.json @@ -11,7 +11,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, diff --git a/pool_configs/helixcoin_example.json b/pool_configs/helixcoin_example.json index 31292a4..3608317 100644 --- a/pool_configs/helixcoin_example.json +++ b/pool_configs/helixcoin_example.json @@ -6,7 +6,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 70, "minimumReserve": 10, "feePercent": 0.05, diff --git a/pool_configs/hirocoin_example.json b/pool_configs/hirocoin_example.json index 9c49962..a963c4b 100644 --- a/pool_configs/hirocoin_example.json +++ b/pool_configs/hirocoin_example.json @@ -6,7 +6,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, diff --git a/pool_configs/hobonickels_example.json b/pool_configs/hobonickels_example.json index bc3e4eb..438bae6 100644 --- a/pool_configs/hobonickels_example.json +++ b/pool_configs/hobonickels_example.json @@ -6,7 +6,7 @@ "internal": { "enabled": false, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, diff --git a/pool_configs/litecoin_example.json b/pool_configs/litecoin_example.json index ce54056..acd9856 100644 --- a/pool_configs/litecoin_example.json +++ b/pool_configs/litecoin_example.json @@ -6,7 +6,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 70, "minimumReserve": 10, "feePercent": 0.05, diff --git a/pool_configs/maxcoin_example.json b/pool_configs/maxcoin_example.json index 9319189..03c8189 100644 --- a/pool_configs/maxcoin_example.json +++ b/pool_configs/maxcoin_example.json @@ -11,7 +11,7 @@ "internal": { "enabled": true, "validateWorkerAddress": true, - "paymentInterval": 10, + "paymentInterval": 60, "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, diff --git a/pool_configs/ultracoin_example.json b/pool_configs/ultracoin_example.json new file mode 100644 index 0000000..2ad473c --- /dev/null +++ b/pool_configs/ultracoin_example.json @@ -0,0 +1,64 @@ +{ + "enabled": false, + "coin": "ultracoin.json", + + "shareProcessing": { + "internal": { + "enabled": true, + "validateWorkerAddress": true, + "paymentInterval": 60, + "minimumPayment": 100.001, + "minimumReserve": 10, + "feePercent": 0.02, + "feeReceiveAddress": "UZ3cz7EKjC4eRKbhiN9tA6xcaDGSVoESc8", + "feeWithdrawalThreshold": 5, + "daemon": { + "host": "localhost", + "port": 18365, + "user": "testuser", + "password": "testpass" + }, + "redis": { + "host": "localhost", + "port": 6379 + } + }, + "mpos": { + "enabled": false, + "host": "localhost", + "port": 3306, + "user": "me", + "password": "mypass", + "database": "ltc", + "stratumAuth": "password" + } + }, + + "address": "UhyKVr4m516TPsrLwm91pYL4f99VGrJ1oC", + "blockRefreshInterval": 1000, + "txRefreshInterval": 20000, + "connectionTimeout": 600, + + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 500, + "purgeInterval": 300 + }, + + "ports": { + "6856": { + "diff": 8 + } + }, + + "daemons": [ + { + "host": "localhost", + "port": 18365, + "user": "testuser", + "password": "testpass" + } + ] +} \ No newline at end of file