From 8e83c32e178a33b2ea7200d55eb5759feefee32b Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 3 Mar 2014 13:51:11 -0700 Subject: [PATCH] Started mysql code for mpos compat. --- README.md | 15 +++-- init.js | 4 +- libs/poolWorker.js | 19 +++--- libs/shareProcessor.js | 77 ++++++++++++++++++++-- package.json | 3 +- pool_configs/litecoin_testnet_example.json | 5 +- 6 files changed, 99 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index bdefdc7..cf0010e 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ balance across multiple CPU cores. For reward/payment processing, shares are inserted into a fast NoSQL key/value database (Redis). Each coin has a processor that monitors for confirmed submitted blocks then send out payments according to shares accumulated in the -database. The payment/reward method used will be PROP (proportional) - where when a block is found, miners are paid -based on their shares submitted during the round (a round is the process of searching for a single block). +database. The payment/reward method used will be PROP (proportional) - where when a block is submitted and confirmed, +miners are paid based on their shares submitted during the round (a round is the process of searching for a single block). For those that wish to use this project with [MPOS](https://github.com/MPOS/php-mpos), the portal can be configured -to insert shares into a MySQL database in the format which MPOS uses. +to insert shares into a MySQL database in the format which MPOS expects. This portal does not have user accounts/logins/registrations. Instead, miners simply use their coin address for stratum authentication. A minimalistic HTML5 front-end connects to the portals statistics API to display stats from from each @@ -92,8 +92,9 @@ Description of options: "enabled": false, "host": "localhost", "port": 3306, - "name": "doge", - "password": "mypass" + "user": "me", + "password": "mypass", + "database": "ltc" }, "internal": { //enabled this options for share payments to be processed and sent locally "enabled": true, @@ -109,8 +110,8 @@ Description of options: } }, - //All options below this are passed directly to the stratum module: - https://github.com/zone117x/node-stratum - which has some additional documentation. + /* All options below this are passed directly to the stratum module: + https://github.com/zone117x/node-stratum - which has some additional documentation. */ "pool": { //instanceId: 37, //Recommend not using this because a crypto-random one will be generated diff --git a/init.js b/init.js index d9dcf46..f5dfc53 100644 --- a/init.js +++ b/init.js @@ -56,7 +56,7 @@ if (cluster.isMaster){ //Read all pool configs from pool_configs and join them with their coin profile var poolConfigs = (function(){ - var configs = []; + var configs = {}; fs.readdirSync('pool_configs').forEach(function(file){ var poolOptions = JSON.parse(JSON.minify(fs.readFileSync('pool_configs/' + file, {encoding: 'utf8'}))); if (poolOptions.disabled) return; @@ -65,7 +65,7 @@ if (cluster.isMaster){ return; } poolOptions.coin = coinProfiles[poolOptions.coin.toLowerCase()]; - configs.push(poolOptions); + configs[poolOptions.coin.name] = poolOptions; }); return configs; })(); diff --git a/libs/poolWorker.js b/libs/poolWorker.js index a5f276e..4d91268 100644 --- a/libs/poolWorker.js +++ b/libs/poolWorker.js @@ -26,11 +26,11 @@ module.exports = function(logger){ }); + Object.keys(poolConfigs).forEach(function(coin) { + var poolOptions = poolConfigs[coin]; - poolConfigs.forEach(function(poolOptions){ - - var logIdentify = poolOptions.coin.name + ' (Fork ' + fork + ')'; + var logIdentify = coin + ' (Fork ' + fork + ')'; var authorizeFN = function (ip, workerName, password, callback) { // Default implementation just returns true @@ -50,23 +50,26 @@ module.exports = function(logger){ if (data.solution && !isValidBlock){ logDebug(logIdentify, 'client', 'We thought a block solution was found but it was rejected by the daemon, share data: ' + shareData); - return; } else if (!isValidShare){ logDebug(logIdentify, 'client', 'Invalid share submitted, share data: ' + shareData) - return; } logDebug(logIdentify, 'client', 'Valid share submitted, share data: ' + shareData); - process.send({type: 'share', share: shareData, coin: poolOptions.coin.name}); + process.send({ + type: 'share', + share: shareData, + coin: poolOptions.coin.name, + isValidShare: isValidShare, + isValidBlock: isValidBlock + }); if (isValidBlock){ logDebug(logIdentify, 'client', 'Block found, solution: ' + shareData.solution); process.send({ type: 'block', share: shareData, - coin: poolOptions.coin.name, - confirmations: poolOptions.rewards.blockConfirmations + coin: poolOptions.coin.name }); } diff --git a/libs/shareProcessor.js b/libs/shareProcessor.js index a9e830b..f033b41 100644 --- a/libs/shareProcessor.js +++ b/libs/shareProcessor.js @@ -2,6 +2,7 @@ var events = require('events'); var cluster = require('cluster'); var redis = require('redis'); +var mysql = require('mysql'); var processor = module.exports = function processor(logger, poolConfigs){ @@ -9,13 +10,81 @@ var processor = module.exports = function processor(logger, poolConfigs){ var client; + var poolMposHandlers = (function(){ + var handlers = {}; + + Object.keys(poolConfigs).forEach(function(coin) { + + var config = poolConfigs[coin]; + + if (!config.shareProcessing || !config.shareProcessing.mpos || !config.shareProcessing.mpos.enabled) + return; + var mposConfig = config.shareProcessing.mpos; + var connection = mysql.createConnection({ + host: mposConfig.host, + port: mposConfig.port, + user: mposConfig.user, + password: mposConfig.password, + database: mposConfig.database + }); + connection.connect(function(err){ + logger.logError('shareProcessor', 'database', config.coin.name + + ' - could not connect to mysql database: ' + JSON.stringify(err)) + }); + connection.on('error', function(err){ + logger.logError('shareProcessor', 'database', config.coin.name + + ' - mysql database error: ' + JSON.stringify(err)) + }); + + var insertShare = function(isValidShare, isValidBlock, data){ + connection.query( + 'INSERT INTO `shares` SET time = NOW(), rem_host = ?, username = ?, our_result = ?, upstream_result = ?, difficulty = ?, reason = ?, solution = ?', + [data.ip, data.worker, isValidShare ? 'Y' : 'N', isValidBlock ? 'Y' : 'N', data.difficulty, data.error, data.solution], + function(err, result) { + if (err) + logger.logError('shareProcessor', 'database', 'MySQL insert error when adding share: ' + + JSON.stringify(err)); + } + ); + }; + + var updateDifficulty = function(workerName, diff){ + connection.query( + 'UPDATE `pool_worker` SET `difficulty` = ' + diff + ' WHERE `username` = ' + connection.escape(workerName), + function(err, result){ + if (err) + logger.logError('shareProcessor', 'database', 'MySQL error when updating worker diff: ' + + JSON.stringify(err)); + else if (result.affectedRows === 0){ + connection.query('INSERT INTO `pool_worker` SET ?', {username: workerName, difficulty: diff}); + } + else + console.log('Updated difficulty successfully', result); + } + ); + }; + + handlers[config.coin.name] = {insertShare: insertShare, updateDifficulty: updateDifficulty}; + }); + return handlers; + })(); + + function handleShare(data){ var shareData = data.share; var coin = data.coin; - client.hincrby([coin + ':' + shareData.height, shareData.worker, shareData.difficulty], function(error, result){ - if (error) - logger.logError('shareProcessor', 'database', 'could not store worker share') - }); + var poolConfig = poolConfigs[coin]; + + if (poolConfig.shareProcessing.mpos && poolConfig.shareProcessing.mpos.enabled){ + poolMposHandlers[coin].insertShare(data.isValidShare, data.isValidBlock, shareData); + } + + if (poolConfig.shareProcessing.internal && poolConfig.shareProcessing.internal.enable && data.isValidShare){ + client.hincrby([coin + ':' + shareData.height, shareData.worker, shareData.difficulty], function(error, result){ + if (error) + logger.logError('shareProcessor', 'database', 'could not store worker share') + }); + } } function handleBlock(data){ diff --git a/package.json b/package.json index 0e71332..e076ad9 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "dateformat": "*", "node-json-minify": "*", "posix": "*", - "redis": "*" + "redis": "*", + "mysql": "felixge/node-mysql", }, "devDependencies": {}, "scripts": { diff --git a/pool_configs/litecoin_testnet_example.json b/pool_configs/litecoin_testnet_example.json index 1b2684c..777f9bc 100644 --- a/pool_configs/litecoin_testnet_example.json +++ b/pool_configs/litecoin_testnet_example.json @@ -6,8 +6,9 @@ "enabled": false, "host": "localhost", "port": 3306, - "name": "doge", - "password": "mypass" + "user": "me", + "password": "mypass", + "database": "ltc" }, "internal": { "enabled": true,