mirror of https://github.com/BTCPrivate/z-nomp.git
Started mysql code for mpos compat.
This commit is contained in:
parent
9376e79a38
commit
8e83c32e17
15
README.md
15
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
|
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
|
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
|
database. The payment/reward method used will be PROP (proportional) - where when a block is submitted and confirmed,
|
||||||
based on their shares submitted during the round (a round is the process of searching for a single block).
|
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
|
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
|
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
|
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,
|
"enabled": false,
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"name": "doge",
|
"user": "me",
|
||||||
"password": "mypass"
|
"password": "mypass",
|
||||||
|
"database": "ltc"
|
||||||
},
|
},
|
||||||
"internal": { //enabled this options for share payments to be processed and sent locally
|
"internal": { //enabled this options for share payments to be processed and sent locally
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
@ -109,8 +110,8 @@ Description of options:
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//All options below this are passed directly to the stratum module:
|
/* All options below this are passed directly to the stratum module:
|
||||||
https://github.com/zone117x/node-stratum - which has some additional documentation.
|
https://github.com/zone117x/node-stratum - which has some additional documentation. */
|
||||||
|
|
||||||
"pool": {
|
"pool": {
|
||||||
//instanceId: 37, //Recommend not using this because a crypto-random one will be generated
|
//instanceId: 37, //Recommend not using this because a crypto-random one will be generated
|
||||||
|
|
4
init.js
4
init.js
|
@ -56,7 +56,7 @@ if (cluster.isMaster){
|
||||||
|
|
||||||
//Read all pool configs from pool_configs and join them with their coin profile
|
//Read all pool configs from pool_configs and join them with their coin profile
|
||||||
var poolConfigs = (function(){
|
var poolConfigs = (function(){
|
||||||
var configs = [];
|
var configs = {};
|
||||||
fs.readdirSync('pool_configs').forEach(function(file){
|
fs.readdirSync('pool_configs').forEach(function(file){
|
||||||
var poolOptions = JSON.parse(JSON.minify(fs.readFileSync('pool_configs/' + file, {encoding: 'utf8'})));
|
var poolOptions = JSON.parse(JSON.minify(fs.readFileSync('pool_configs/' + file, {encoding: 'utf8'})));
|
||||||
if (poolOptions.disabled) return;
|
if (poolOptions.disabled) return;
|
||||||
|
@ -65,7 +65,7 @@ if (cluster.isMaster){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
poolOptions.coin = coinProfiles[poolOptions.coin.toLowerCase()];
|
poolOptions.coin = coinProfiles[poolOptions.coin.toLowerCase()];
|
||||||
configs.push(poolOptions);
|
configs[poolOptions.coin.name] = poolOptions;
|
||||||
});
|
});
|
||||||
return configs;
|
return configs;
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -26,11 +26,11 @@ module.exports = function(logger){
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Object.keys(poolConfigs).forEach(function(coin) {
|
||||||
|
|
||||||
|
var poolOptions = poolConfigs[coin];
|
||||||
|
|
||||||
poolConfigs.forEach(function(poolOptions){
|
var logIdentify = coin + ' (Fork ' + fork + ')';
|
||||||
|
|
||||||
var logIdentify = poolOptions.coin.name + ' (Fork ' + fork + ')';
|
|
||||||
|
|
||||||
var authorizeFN = function (ip, workerName, password, callback) {
|
var authorizeFN = function (ip, workerName, password, callback) {
|
||||||
// Default implementation just returns true
|
// Default implementation just returns true
|
||||||
|
@ -50,23 +50,26 @@ module.exports = function(logger){
|
||||||
|
|
||||||
if (data.solution && !isValidBlock){
|
if (data.solution && !isValidBlock){
|
||||||
logDebug(logIdentify, 'client', 'We thought a block solution was found but it was rejected by the daemon, share data: ' + shareData);
|
logDebug(logIdentify, 'client', 'We thought a block solution was found but it was rejected by the daemon, share data: ' + shareData);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else if (!isValidShare){
|
else if (!isValidShare){
|
||||||
logDebug(logIdentify, 'client', 'Invalid share submitted, share data: ' + shareData)
|
logDebug(logIdentify, 'client', 'Invalid share submitted, share data: ' + shareData)
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug(logIdentify, 'client', 'Valid share submitted, share data: ' + shareData);
|
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){
|
if (isValidBlock){
|
||||||
logDebug(logIdentify, 'client', 'Block found, solution: ' + shareData.solution);
|
logDebug(logIdentify, 'client', 'Block found, solution: ' + shareData.solution);
|
||||||
process.send({
|
process.send({
|
||||||
type: 'block',
|
type: 'block',
|
||||||
share: shareData,
|
share: shareData,
|
||||||
coin: poolOptions.coin.name,
|
coin: poolOptions.coin.name
|
||||||
confirmations: poolOptions.rewards.blockConfirmations
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ var events = require('events');
|
||||||
var cluster = require('cluster');
|
var cluster = require('cluster');
|
||||||
|
|
||||||
var redis = require('redis');
|
var redis = require('redis');
|
||||||
|
var mysql = require('mysql');
|
||||||
|
|
||||||
var processor = module.exports = function processor(logger, poolConfigs){
|
var processor = module.exports = function processor(logger, poolConfigs){
|
||||||
|
|
||||||
|
@ -9,13 +10,81 @@ var processor = module.exports = function processor(logger, poolConfigs){
|
||||||
|
|
||||||
var client;
|
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){
|
function handleShare(data){
|
||||||
var shareData = data.share;
|
var shareData = data.share;
|
||||||
var coin = data.coin;
|
var coin = data.coin;
|
||||||
client.hincrby([coin + ':' + shareData.height, shareData.worker, shareData.difficulty], function(error, result){
|
var poolConfig = poolConfigs[coin];
|
||||||
if (error)
|
|
||||||
logger.logError('shareProcessor', 'database', 'could not store worker share')
|
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){
|
function handleBlock(data){
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
"dateformat": "*",
|
"dateformat": "*",
|
||||||
"node-json-minify": "*",
|
"node-json-minify": "*",
|
||||||
"posix": "*",
|
"posix": "*",
|
||||||
"redis": "*"
|
"redis": "*",
|
||||||
|
"mysql": "felixge/node-mysql",
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"name": "doge",
|
"user": "me",
|
||||||
"password": "mypass"
|
"password": "mypass",
|
||||||
|
"database": "ltc"
|
||||||
},
|
},
|
||||||
"internal": {
|
"internal": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|
Loading…
Reference in New Issue