Working on stats and payment processing

This commit is contained in:
Matt 2014-03-15 18:58:28 -06:00
parent 912e3682be
commit ed9e61b8ee
11 changed files with 183 additions and 49 deletions

View File

@ -313,11 +313,11 @@ For more information on these configuration options see the [pool module documen
1. In `config.json` set the port and password for `blockNotifyListener`
2. In your daemon conf file set the `blocknotify` command to use:
```
[path to scripts/blockNotify.js] [listener host]:[listener port] [listener password] [coin name in config] %s
node [path to scripts/blockNotify.js] [listener host]:[listener port] [listener password] [coin name in config] %s
```
Example: inside `dogecoin.conf` add the line
```
blocknotify="scripts/blockNotify.js localhost:8117 mySuperSecurePassword dogecoin %s"
blocknotify="node scripts/blockNotify.js localhost:8117 mySuperSecurePassword dogecoin %s"
```
@ -344,6 +344,14 @@ To support development of this project feel free to donate :)
BTC: 1KRotMnQpxu3sePQnsVLRy3EraRFYfJQFR
Credits
-------
* [vekexasia](https://github.com/vekexasia) - co-developer & great tester
* [TheSeven](https://github.com/TheSeven) - answering an absurd amount of my questions and being a very helpful and king gentleman
* Those that contributed to [node-stratum](/zone117x/node-stratum)
License
-------
Released under the GNU General Public License v2

View File

@ -2,7 +2,7 @@
"logLevel": "debug",
"clustering": {
"enabled": true,
"forks": "1"
"forks": "auto"
},
"blockNotifyListener": {
"enabled": false,
@ -16,8 +16,13 @@
"redisHost" : "hostname",
"psubscribeKey" : "newblocks:*"
},
"website": {
"enabled": false,
"port": 80,
"statUpdateInterval": 3
},
"proxy": {
"enabled": true,
"enabled": false,
"ports": {
"80": {
"diff": 32,
@ -50,10 +55,5 @@
}
}
}
},
"website": {
"enabled": false,
"port": 80,
"liveStats": true
}
}

View File

@ -150,6 +150,9 @@ var startBlockListener = function(portalConfig){
var startRedisBlockListener = function(portalConfig){
//block notify options
//setup block notify here and use IPC to tell appropriate pools
if (!portalConfig.redisBlockNotifyListener.enabled) return;
var listener = new RedisBlocknotifyListener(portalConfig.redisBlockNotifyListener);
listener.on('log', function(text){
logDebug('blocknotify', 'system', text);
@ -178,7 +181,6 @@ var startPaymentProcessor = function(poolConfigs){
var startWebsite = function(portalConfig, poolConfigs){
console.log(portalConfig.website);
if (!portalConfig.website.enabled) return;
@ -209,7 +211,6 @@ var startWebsite = function(portalConfig, poolConfigs){
startRedisBlockListener(portalConfig);
startWorkerListener(poolConfigs);
;
startWebsite(portalConfig, poolConfigs);

View File

@ -40,8 +40,20 @@ module.exports = function(logger, poolConfigs){
setInterval(clearExpiredHashrates, 10 * 60 * 1000);
clearExpiredHashrates();
this.getStats = function(callback){
/*
{ global: {
}
*/
//get stats like hashrate and in/valid shares/blocks and workers in current round
};

View File

@ -53,11 +53,11 @@ 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

View File

@ -79,6 +79,48 @@ function SetupForPool(logger, poolOptions){
connectToRedis();
/* When blocks or orphaned, all shares contributed to that round would receive no reward. That doesn't seem fair
so we still all the shares from an orphaned rounds into the current round.
*/
var adoptOrphanRounds = function(rounds){
var shareLookups = rounds.map(function(r){
return ['hgetall', coin + '_shares:round' + r.height]
});
var shareIncries = [];
redisClient.multi(shareLookups).exec(function(error, allWorkerShares){
if (error){
paymentLogger.error('redis', 'Error with multi get rounds share for adopting orphan');
return;
}
var workerRewards = {};
for (var i = 0; i < rounds.length; i++){
var round = rounds[i];
var workerShares = allWorkerShares[i];
var reward = round.reward * (1 - processingConfig.feePercent);
var totalShares = Object.keys(workerShares).reduce(function(p, c){
return p + parseInt(workerShares[c])
}, 0);
for (var worker in workerShares){
var percent = parseInt(workerShares[worker]) / totalShares;
var workerRewardTotal = Math.floor(reward * percent);
if (!(worker in workerRewards)) workerRewards[worker] = 0;
workerRewards[worker] += workerRewardTotal;
}
}
});
};
var processPayments = function(){
@ -125,29 +167,61 @@ function SetupForPool(logger, poolOptions){
return;
}
for (var i = txDetails.length; i > 0; --i){
var tx = txDetails[i];
if (tx.error || !tx.result){
console.log('error with requesting transaction from block daemon: ' + JSON.stringify(t));
txDetails.splice(i, 1);
}
}
var orphanedRounds = [];
var confirmedRounds = [];
//Rounds that are not confirmed yet are removed from the round array
//We also get reward amount for each block from daemon reply
rounds = rounds.filter(function(r){
var tx = txDetails.filter(function(t){ return t.result.txid === r.txHash; })[0];
if (tx.result.details[0].category !== 'generate') return false;
r.amount = tx.result.amount;
r.magnitude = r.reward / r.amount;
return true;
rounds.forEach(function(r){
var tx = txDetails.filter(function(tx){return tx.result.txid === r.txHash})[0];
if (!tx){
console.log('daemon did not give us back a transaction that we asked for: ' + r.txHash);
return;
}
r.category = tx.result.details[0].category;
if (r.category === 'orphan'){
orphanedRounds.push(r);
}
else if (r.category === 'generate'){
r.amount = tx.result.amount;
r.magnitude = r.reward / r.amount;
confirmedRounds.push(r);
}
});
if (rounds.length === 0){
callback('done - no confirmed transactions yet');
return;
if (orphanedRounds.length === 0 && confirmedRounds.length === 0){
callback('done - no confirmed or orhpaned rounds');
}
else{
callback(null, confirmedRounds, orphanedRounds);
}
callback(null, rounds);
});
},
/* Does a batch redis call to get shares contributed to each round. Then calculates the reward
amount owned to each miner for each round. */
function(rounds, callback){
function(confirmedRounds, orphanedRounds, callback){
var rounds = [];
for (var i = 0; i < orphanedRounds; i++) rounds.push(orphanedRounds[i]);
for (var i = 0; i < confirmedRounds; i++) rounds.push(confirmedRounds[i]);
var shareLookups = rounds.map(function(r){
@ -160,6 +234,16 @@ function SetupForPool(logger, poolOptions){
return;
}
var orphanMergeCommands = []
for (var i = 0; i < orphanedRounds.length; i++){
var workerShares = allWorkerShares[i];
Object.keys(workerShares).forEach(function(worker){
orphanMergeCommands.push(['hincrby', coin + '_shares:roundCurrent', worker, workerShares[worker]]);
});
orphanMergeCommands.push([]);
}
var workerRewards = {};

View File

@ -94,10 +94,9 @@ module.exports = function(logger){
var shareProcessor = new ShareProcessor(poolLogger, poolOptions)
handlers.auth = function(workerName, password, authCallback){
authCallback({
error: null,
authorized: true,
disconnect: false
pool.daemon.cmd('validateaddress', [workerName], function(results){
var isValid = results.filter(function(r){return r.response.isvalid}).length > 0;
authCallback(isValid);
});
};

View File

@ -74,10 +74,7 @@ module.exports = function(logger, poolConfig){
connection.multi(redisCommands).exec(function(err, replies){
if (err)
console.log('error with share processor multi ' + JSON.stringify(err));
else{
console.log(JSON.stringify(replies));
}
logger.error('redis', 'error with share processor multi ' + JSON.stringify(err));
});

View File

@ -1,5 +1,5 @@
{
"disabled": true,
"disabled": false,
"coin": "litecoin.json",
"shareProcessing": {
@ -48,8 +48,8 @@
},
"ports": {
"3032": {
"diff": 32,
"3008":{
"diff": 8,
"varDiff": {
"minDiff": 8,
"maxDiff": 512,
@ -58,6 +58,9 @@
"variancePercent": 30
}
},
"3032": {
"diff": 32
},
"3256": {
"diff": 256
}

View File

@ -1,13 +1,10 @@
#!/usr/bin/env node
/**
* This script should be hooked to the coin daemon as follow:
*
* litecoind -blocknotify="/path/to/this/script/blockNotify.js localhost:8117 password litecoin %s"
*
* The above will send tell litecoin to launch this script with those parameters every time
* a block is found.
* This script will then send the blockhash along with other informations to a listening tcp socket
**/
/*
This script should be hooked to the coin daemon as follow:
litecoind -blocknotify="node /path/to/this/script/blockNotify.js localhost:8117 password litecoin %s"
The above will send tell litecoin to launch this script with those parameters every time a block is found.
This script will then send the blockhash along with other information to a listening tcp socket
*/
var net = require('net');
var config = process.argv[1];

33
statsExampleJson.js Normal file
View File

@ -0,0 +1,33 @@
var stats = {
global:{
hashrate: 1000, //in KH/s
validShares: 1,
invalidShares: 1,
validBlocks: 1,
invalidBlocks: 1,
blocksPending: 1,
blocksConfirmed: 1,
blocksOrphaned: 1,
connectedMiners: 344
},
pools:[
{
coin: "Dogecoin",
sybmol: 'doge',
stats:{
hashrate: 1000, //in KH/s
validShares: 1,
invalidShares: 1,
validBlocks: 1,
invalidBlocks: 1,
blocksPending: 1,
blocksConfirmed: 1,
blocksOrphaned: 1,
connectedMiners: 34545,
totalPayedOut: 3343.789797
}
}
]
}