mirror of https://github.com/BTCPrivate/z-nomp.git
Working on stats and payment processing
This commit is contained in:
parent
912e3682be
commit
ed9e61b8ee
12
README.md
12
README.md
|
@ -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
|
||||
|
|
14
config.json
14
config.json
|
@ -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
|
||||
}
|
||||
}
|
5
init.js
5
init.js
|
@ -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);
|
||||
|
||||
|
|
12
libs/api.js
12
libs/api.js
|
@ -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
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
}
|
Loading…
Reference in New Issue