mirror of https://github.com/BTCPrivate/z-nomp.git
coins: added requireShielding boolean
coins: updated zcash_testnet founders addresses configs: added komodo_example.conf api.js: added payments json api call stats.js: improved getTotalSharesByAdress to support multiple coins. stats.js: report more collected stats stats.js: report payment stats stats.js: optimizations to historical data saving paymentProcessor.js: added requireShielding support paymentProcessor.js: added support to pay directly from komodo pool address without shielding first paymentProcessor.js: lower tx fee reserve for komodo to 0.00005 KMD paymentProcessor.js: tx fee reserve for all coins is 0.0004 paymentProcessor.js: improved multi-coin support paymentProcessor.js: added minConfShield and minConfPayout variables paymentProcessor.js: updated coin network stat caching paymentProcessor.js: improved operation id handling when shielding coins paymentProcessor.js: updated coin network stat caching paymentProcessor.js: updated payment stat collection in redis miner_stats.html: removed ZEC references
This commit is contained in:
parent
24f48be37c
commit
c04bcf166d
|
@ -2,7 +2,7 @@
|
|||
"name": "zcash",
|
||||
"symbol": "zec",
|
||||
"algorithm": "equihash",
|
||||
|
||||
"requireShielding": true,
|
||||
"payFoundersReward": true,
|
||||
"percentFoundersReward": 20,
|
||||
"maxFoundersRewardBlockHeight": 849999,
|
||||
|
|
|
@ -2,23 +2,23 @@
|
|||
"name": "zcash_testnet",
|
||||
"symbol": "taz",
|
||||
"algorithm": "equihash",
|
||||
|
||||
"requireShielding": true,
|
||||
"payFoundersReward": true,
|
||||
"percentFoundersReward": 20,
|
||||
"maxFoundersRewardBlockHeight": 849999,
|
||||
"foundersRewardAddressChangeInterval": 17709.3125,
|
||||
"vFoundersRewardAddress": [
|
||||
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy",
|
||||
"t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9",
|
||||
"t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo",
|
||||
"t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK",
|
||||
"t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC",
|
||||
"t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH",
|
||||
"t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a",
|
||||
"t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J",
|
||||
"t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t",
|
||||
"t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy",
|
||||
"t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4",
|
||||
"t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt"
|
||||
]
|
||||
"vFoundersRewardAddress": [
|
||||
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543", "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2", "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy",
|
||||
"t2BkYdVCHzvTJJUTx4yZB8qeegD8QsPx8bo", "t2J8q1xH1EuigJ52MfExyyjYtN3VgvshKDf", "t2Crq9mydTm37kZokC68HzT6yez3t2FBnFj", "t2EaMPUiQ1kthqcP5UEkF42CAFKJqXCkXC9",
|
||||
"t2F9dtQc63JDDyrhnfpzvVYTJcr57MkqA12", "t2LPirmnfYSZc481GgZBa6xUGcoovfytBnC", "t26xfxoSw2UV9Pe5o3C8V4YybQD4SESfxtp", "t2D3k4fNdErd66YxtvXEdft9xuLoKD7CcVo",
|
||||
"t2DWYBkxKNivdmsMiivNJzutaQGqmoRjRnL", "t2C3kFF9iQRxfc4B9zgbWo4dQLLqzqjpuGQ", "t2MnT5tzu9HSKcppRyUNwoTp8MUueuSGNaB", "t2AREsWdoW1F8EQYsScsjkgqobmgrkKeUkK",
|
||||
"t2Vf4wKcJ3ZFtLj4jezUUKkwYR92BLHn5UT", "t2K3fdViH6R5tRuXLphKyoYXyZhyWGghDNY", "t2VEn3KiKyHSGyzd3nDw6ESWtaCQHwuv9WC", "t2F8XouqdNMq6zzEvxQXHV1TjwZRHwRg8gC",
|
||||
"t2BS7Mrbaef3fA4xrmkvDisFVXVrRBnZ6Qj", "t2FuSwoLCdBVPwdZuYoHrEzxAb9qy4qjbnL", "t2SX3U8NtrT6gz5Db1AtQCSGjrpptr8JC6h", "t2V51gZNSoJ5kRL74bf9YTtbZuv8Fcqx2FH",
|
||||
"t2FyTsLjjdm4jeVwir4xzj7FAkUidbr1b4R", "t2EYbGLekmpqHyn8UBF6kqpahrYm7D6N1Le", "t2NQTrStZHtJECNFT3dUBLYA9AErxPCmkka", "t2GSWZZJzoesYxfPTWXkFn5UaxjiYxGBU2a",
|
||||
"t2RpffkzyLRevGM3w9aWdqMX6bd8uuAK3vn", "t2JzjoQqnuXtTGSN7k7yk5keURBGvYofh1d", "t2AEefc72ieTnsXKmgK2bZNckiwvZe3oPNL", "t2NNs3ZGZFsNj2wvmVd8BSwSfvETgiLrD8J",
|
||||
"t2ECCQPVcxUCSSQopdNquguEPE14HsVfcUn", "t2JabDUkG8TaqVKYfqDJ3rqkVdHKp6hwXvG", "t2FGzW5Zdc8Cy98ZKmRygsVGi6oKcmYir9n", "t2DUD8a21FtEFn42oVLp5NGbogY13uyjy9t",
|
||||
"t2UjVSd3zheHPgAkuX8WQW2CiC9xHQ8EvWp", "t2TBUAhELyHUn8i6SXYsXz5Lmy7kDzA1uT5", "t2Tz3uCyhP6eizUWDc3bGH7XUC9GQsEyQNc", "t2NysJSZtLwMLWEJ6MH3BsxRh6h27mNcsSy",
|
||||
"t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4",
|
||||
"t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
"name": "zclassic",
|
||||
"symbol": "zcl",
|
||||
"algorithm": "equihash",
|
||||
"requireShielding": true,
|
||||
"peerMagic": "24e92764"
|
||||
}
|
||||
|
|
|
@ -19,6 +19,13 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
return;
|
||||
case 'pool_stats':
|
||||
res.end(JSON.stringify(portalStats.statPoolHistory));
|
||||
return;
|
||||
case 'payments':
|
||||
var poolBlocks = [];
|
||||
for(var pool in portalStats.stats.pools) {
|
||||
poolBlocks.push({name: pool, pending: portalStats.stats.pools[pool].pending, payments: portalStats.stats.pools[pool].payments});
|
||||
}
|
||||
res.end(JSON.stringify(poolBlocks));
|
||||
return;
|
||||
case 'worker_stats':
|
||||
if (req.url.indexOf("?")>0) {
|
||||
|
@ -56,7 +63,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
//console.log(portalStats.statHistory[h].time);
|
||||
}
|
||||
}
|
||||
// note, h is the last record from above loop, which is latest
|
||||
for(var pool in portalStats.stats.pools) {
|
||||
for(var w in portalStats.stats.pools[pool].workers){
|
||||
if (w.startsWith(address)) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var fs = require('fs');
|
||||
var request = require("request");
|
||||
|
||||
var redis = require('redis');
|
||||
var async = require('async');
|
||||
|
@ -50,6 +51,13 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
var logSystem = 'Payments';
|
||||
var logComponent = coin;
|
||||
var opidCount = 0;
|
||||
|
||||
var minConfShield = 3;
|
||||
var minConfPayout = 10;
|
||||
|
||||
var requireShielding = poolOptions.coin.requireShielding === true;
|
||||
|
||||
logger.special(logSystem, logComponent, logComponent + ' requireShielding: ' + requireShielding);
|
||||
|
||||
var daemon = new Stratum.daemon.interface([processingConfig.daemon], function(severity, message){
|
||||
logger[severity](logSystem, logComponent, message);
|
||||
|
@ -279,111 +287,122 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
);
|
||||
}
|
||||
|
||||
function cacheZCashNetworkStats () {
|
||||
|
||||
function cacheNetworkStats () {
|
||||
var params = null;
|
||||
daemon.cmd('getmininginfo', params,
|
||||
function (result) {
|
||||
var finalRedisCommands = [];
|
||||
var coin = logComponent;
|
||||
|
||||
if (result.error) {
|
||||
logger.error(logSystem, logComponent, 'Error getting stats from zcashd'
|
||||
logger.error(logSystem, logComponent, 'Error with RPC call `getmininginfo`'
|
||||
+ JSON.stringify(result.error));
|
||||
return;
|
||||
} else {
|
||||
logger.special(logSystem, logComponent, "Updating "+logComponent+" network stats...");
|
||||
var coin = logComponent;
|
||||
var finalRedisCommands = [];
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networksolps]);
|
||||
redisClient.multi(finalRedisCommands).exec(function(error, results){
|
||||
if (error){
|
||||
logger.error(logSystem, logComponent, 'Could not update zcash stats to redis ' + JSON.stringify(error));
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (result[0].response.blocks !== null) {
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networksolps]);
|
||||
} else {
|
||||
logger.error(logSystem, logComponent, "Error parse RPC call reponse.blocks tp `getmininginfo`." + JSON.stringify(result[0].response));
|
||||
}
|
||||
}
|
||||
daemon.cmd('getinfo', params,
|
||||
|
||||
daemon.cmd('getnetworkinfo', params,
|
||||
function (result) {
|
||||
if (result.error) {
|
||||
logger.error(logSystem, logComponent, 'Error getting stats from zcashd'
|
||||
logger.error(logSystem, logComponent, 'Error with RPC call `getnetworkinfo`'
|
||||
+ JSON.stringify(result.error));
|
||||
return;
|
||||
} else {
|
||||
var coin = logComponent;
|
||||
var finalRedisCommands = [];
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]);
|
||||
redisClient.multi(finalRedisCommands).exec(function(error, results){
|
||||
if (error){
|
||||
logger.error(logSystem, logComponent, 'Could not update zcash stats to redis ' + JSON.stringify(error));
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (result[0].response !== null) {
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkVersion', result[0].response.version]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkSubVersion', result[0].response.subversion]);
|
||||
finalRedisCommands.push(['hset', coin + ':stats', 'networkProtocolVersion', result[0].response.protocolversion]);
|
||||
} else {
|
||||
logger.error(logSystem, logComponent, "Error parse RPC call response to `getnetworkinfo`." + JSON.stringify(result[0].response));
|
||||
}
|
||||
}
|
||||
redisClient.multi(finalRedisCommands).exec(function(error, results){
|
||||
if (error){
|
||||
logger.error(logSystem, logComponent, 'Error update coin stats to redis ' + JSON.stringify(error));
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// run coinbase coin transfers every x minutes
|
||||
var intervalState = 0; // do not send ZtoT and TtoZ and same time, this results in operation failed!
|
||||
var interval = poolOptions.walletInterval * 60 * 1000; // run every x minutes
|
||||
setInterval(function() {
|
||||
intervalState++;
|
||||
switch (intervalState){
|
||||
case 1:
|
||||
listUnspent(poolOptions.address, null, 1, false, sendTToZ);
|
||||
break;
|
||||
default:
|
||||
listUnspentZ(poolOptions.zAddress, 1, false, sendZToT);
|
||||
//listUnspent(null, poolOptions.address, 1, true, function (){});
|
||||
intervalState = 0;
|
||||
break;
|
||||
// shielding not required for some equihash coins
|
||||
if (requireShielding === true) {
|
||||
intervalState++;
|
||||
switch (intervalState) {
|
||||
case 1:
|
||||
listUnspent(poolOptions.address, null, minConfShield, false, sendTToZ);
|
||||
break;
|
||||
default:
|
||||
listUnspentZ(poolOptions.zAddress, minConfShield, false, sendZToT);
|
||||
intervalState = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// update zcash stats
|
||||
cacheZCashNetworkStats();
|
||||
// update network stats using coin daemon
|
||||
cacheNetworkStats();
|
||||
}, interval);
|
||||
|
||||
|
||||
// check operation statuses every x seconds
|
||||
var opid_interval = poolOptions.walletInterval * 1000;
|
||||
setInterval(function(){
|
||||
var checkOpIdSuccessAndGetResult = function(ops) {
|
||||
ops.forEach(function(op, i){
|
||||
if (op.status == "success" || op.status == "failed") {
|
||||
daemon.cmd('z_getoperationresult', [[op.id]], function (result) {
|
||||
if (result.error) {
|
||||
logger.warning(logSystem, logComponent, 'Unable to get payment operation id result ' + JSON.stringify(result));
|
||||
}
|
||||
if (result.response) {
|
||||
if (opidCount > 0) {
|
||||
opidCount = 0;
|
||||
// shielding not required for some equihash coins
|
||||
if (requireShielding === true) {
|
||||
setInterval(function(){
|
||||
var checkOpIdSuccessAndGetResult = function(ops) {
|
||||
ops.forEach(function(op, i){
|
||||
if (op.status == "success" || op.status == "failed") {
|
||||
daemon.cmd('z_getoperationresult', [[op.id]], function (result) {
|
||||
if (result.error) {
|
||||
logger.warning(logSystem, logComponent, 'Unable to get payment operation id result ' + JSON.stringify(result));
|
||||
}
|
||||
if (op.status == "failed") {
|
||||
if (op.error) {
|
||||
logger.error(logSystem, logComponent, "Payment operation failed " + op.id + " " + op.error.code +", " + op.error.message);
|
||||
} else {
|
||||
logger.error(logSystem, logComponent, "Payment operation failed " + op.id);
|
||||
if (result.response) {
|
||||
if (opidCount > 0) {
|
||||
opidCount = 0;
|
||||
}
|
||||
if (op.status == "failed") {
|
||||
if (op.error) {
|
||||
logger.error(logSystem, logComponent, "Payment operation failed " + op.id + " " + op.error.code +", " + op.error.message);
|
||||
} else {
|
||||
logger.error(logSystem, logComponent, "Payment operation failed " + op.id);
|
||||
}
|
||||
} else {
|
||||
logger.special(logSystem, logComponent, 'Payment operation success ' + op.id + ' txid: ' + op.result.txid);
|
||||
}
|
||||
} else {
|
||||
logger.special(logSystem, logComponent, 'Payment operation success ' + op.id + ' txid: ' + op.result.txid);
|
||||
}
|
||||
}, true, true);
|
||||
} else if (op.status == "executing") {
|
||||
if (opidCount == 0) {
|
||||
opidCount++;
|
||||
logger.special(logSystem, logComponent, 'Payment operation in progress ' + op.id );
|
||||
}
|
||||
}, true, true);
|
||||
} else if (op.status == "executing") {
|
||||
if (opidCount == 0) {
|
||||
opidCount++;
|
||||
logger.special(logSystem, logComponent, 'Payment operation in progress ' + op.id );
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
daemon.cmd('z_getoperationstatus', null, function (result) {
|
||||
if (result.error) {
|
||||
logger.warning(logSystem, logComponent, 'Unable to get operation ids for clearing.');
|
||||
}
|
||||
if (result.response) {
|
||||
checkOpIdSuccessAndGetResult(result.response);
|
||||
}
|
||||
}, true, true);
|
||||
}, opid_interval);
|
||||
|
||||
});
|
||||
};
|
||||
daemon.cmd('z_getoperationstatus', null, function (result) {
|
||||
if (result.error) {
|
||||
logger.warning(logSystem, logComponent, 'Unable to get operation ids for clearing.');
|
||||
}
|
||||
if (result.response) {
|
||||
checkOpIdSuccessAndGetResult(result.response);
|
||||
}
|
||||
}, true, true);
|
||||
}, opid_interval);
|
||||
}
|
||||
|
||||
var satoshisToCoins = function(satoshis){
|
||||
return parseFloat((satoshis / magnitude).toFixed(coinPrecision));
|
||||
|
@ -478,7 +497,7 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
}
|
||||
|
||||
// update confirmations in redis for pending blocks
|
||||
var confirmsUpdate = blockDetails.map(function(b){
|
||||
var confirmsUpdate = blockDetails.map(function(b) {
|
||||
if (b.result != null && b.result.confirmations > 0) {
|
||||
if (b.result.confirmations > 100) {
|
||||
return ['hdel', logComponent + ':blocksPendingConfirms', b.result.hash];
|
||||
|
@ -609,10 +628,16 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
+ round.txHash);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TODO, estimate transaction fees, make dynamic
|
||||
var fee = 0.00005; // komodo
|
||||
if (logComponent != "komodo") {
|
||||
fee = 0.0004; // all other coins
|
||||
}
|
||||
|
||||
round.category = generationTx.category;
|
||||
if (round.category === 'generate') {
|
||||
round.reward = generationTx.amount - 0.0004 || generationTx.value - 0.0004; // TODO: Adjust fees to be dynamic
|
||||
round.reward = balanceRound(generationTx.amount - fee) || balanceRound(generationTx.value - fee); // TODO: Adjust fees to be dynamic
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -643,18 +668,32 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
}
|
||||
});
|
||||
|
||||
// check if we have enough tAddress funds to send payments
|
||||
var totalOwed = 0;
|
||||
for (var i = 0; i < rounds.length; i++) {
|
||||
totalOwed = totalOwed + (rounds[i].reward * magnitude) - 4000; // TODO: make tx fees dynamic
|
||||
// TODO, estimate transaction fees, make dynamic
|
||||
var fee = 500; // komodo
|
||||
if (logComponent != "komodo") {
|
||||
fee = 4000; // all other coins
|
||||
}
|
||||
|
||||
listUnspent(null, poolOptions.address, 1, false, function (error, tBalance){
|
||||
if (tBalance < totalOwed) {
|
||||
logger.error(logSystem, logComponent, (tBalance / magnitude).toFixed(8) + ' is not enough payment funds to process ' + (totalOwed / magnitude).toFixed(8) + ' of payments. (Possibly due to pending txs)');
|
||||
// calculate what the pool owes its miners
|
||||
var totalOwed = parseInt(0);
|
||||
for (var i = 0; i < rounds.length; i++) {
|
||||
totalOwed = totalOwed + Math.round(rounds[i].reward * magnitude) - fee; // TODO: make tx fees dynamic
|
||||
}
|
||||
|
||||
var notAddr = null;
|
||||
if (requireShielding === true) {
|
||||
notAddr = poolOptions.address;
|
||||
}
|
||||
|
||||
// check if we have enough tAddress funds to brgin payment processing
|
||||
listUnspent(null, notAddr, minConfPayout, false, function (error, tBalance){
|
||||
if (error) {
|
||||
logger.error(logSystem, logComponent, 'Error checking pool balance before payouts. (Unable to begin payment process)');
|
||||
return callback(true);
|
||||
} else if (tBalance < totalOwed) {
|
||||
logger.error(logSystem, logComponent, 'Insufficient pool funds to being payment process; '+(tBalance / magnitude).toFixed(8) + ' < ' + (totalOwed / magnitude).toFixed(8)+'. (Possibly due to pending txs) ');
|
||||
return callback(true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// zcash daemon does not support account feature
|
||||
addressAccount = "";
|
||||
callback(null, workers, rounds, addressAccount);
|
||||
|
@ -851,7 +890,7 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
return parseInt(r.height);
|
||||
});
|
||||
var paymentsUpdate = [];
|
||||
var paymentsData = [{txid:txid, paid:balanceRound(totalSent / magnitude), shares:totalShares, miners:Object.keys(addressAmounts).length}, {blocks: paymentBlocks}, addressAmounts];
|
||||
var paymentsData = {time:Date.now(), txid:txid, shares:totalShares, paid:balanceRound(totalSent / magnitude), miners:Object.keys(addressAmounts).length, blocks: paymentBlocks, amounts: addressAmounts};
|
||||
paymentsUpdate.push(['zadd', logComponent + ':payments', Date.now(), JSON.stringify(paymentsData)]);
|
||||
startRedisTimer();
|
||||
redisClient.multi(paymentsUpdate).exec(function(error, payments){
|
||||
|
@ -882,11 +921,12 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
},
|
||||
function(workers, rounds, callback){
|
||||
|
||||
var totalPaid = 0;
|
||||
var totalPaid = parseFloat(0);
|
||||
|
||||
var balanceUpdateCommands = [];
|
||||
var workerPayoutsCommand = [];
|
||||
|
||||
// update worker paid/balance stats
|
||||
for (var w in workers) {
|
||||
var worker = workers[w];
|
||||
if (worker.balanceChange !== 0){
|
||||
|
@ -916,6 +956,7 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
}
|
||||
};
|
||||
|
||||
// handle the round
|
||||
rounds.forEach(function(r){
|
||||
switch(r.category){
|
||||
case 'kicked':
|
||||
|
@ -994,5 +1035,4 @@ function SetupForPool(logger, poolOptions, setupFinished){
|
|||
else return address;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ var zlib = require('zlib');
|
|||
|
||||
var redis = require('redis');
|
||||
var async = require('async');
|
||||
//var fancyTimestamp = require('fancy-timestamp');
|
||||
|
||||
var os = require('os');
|
||||
|
||||
|
@ -176,11 +175,18 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
var client = redisClients[0].client,
|
||||
coins = redisClients[0].coins,
|
||||
shares = [];
|
||||
var totalShares = 0;
|
||||
|
||||
var pindex = parseInt(0);
|
||||
var totalShares = parseFloat(0);
|
||||
async.each(_this.stats.pools, function(pool, pcb) {
|
||||
pindex++;
|
||||
var coin = String(_this.stats.pools[pool.name].name);
|
||||
client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", function(error, result) {
|
||||
var workerName = "";
|
||||
if (error) {
|
||||
pcb(error);
|
||||
return;
|
||||
}
|
||||
var workerName="";
|
||||
var shares = 0;
|
||||
for (var i in result[1]) {
|
||||
if (Math.abs(i % 2) != 1) {
|
||||
|
@ -189,15 +195,20 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
shares += parseFloat(result[1][i]);
|
||||
}
|
||||
}
|
||||
totalShares = shares;
|
||||
pcb();
|
||||
if (shares>0) {
|
||||
totalShares = shares;
|
||||
}
|
||||
pcb();
|
||||
});
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
cback(0);
|
||||
return;
|
||||
}
|
||||
cback(totalShares);
|
||||
if (err) {
|
||||
cback(0);
|
||||
return;
|
||||
}
|
||||
if (totalShares > 0 || (pindex >= Object.keys(_this.stats.pools).length)) {
|
||||
cback(totalShares);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -285,7 +296,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
['smembers', ':blocksConfirmed'],
|
||||
['hgetall', ':shares:roundCurrent'],
|
||||
['hgetall', ':blocksPendingConfirms'],
|
||||
['hgetall', ':payments']
|
||||
['zrange', ':payments', -100, -1]
|
||||
];
|
||||
|
||||
var commandsPerCoin = redisCommandTemplates.length;
|
||||
|
@ -320,23 +331,31 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
networkSols: replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0,
|
||||
networkSolsString: getReadableNetworkHashRateString(replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0),
|
||||
networkDiff: replies[i + 2] ? (replies[i + 2].networkDiff || 0) : 0,
|
||||
networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0
|
||||
networkConnections: replies[i + 2] ? (replies[i + 2].networkConnections || 0) : 0,
|
||||
networkVersion: replies[i + 2] ? (replies[i + 2].networkSubVersion || 0) : 0,
|
||||
networkProtocolVersion: replies[i + 2] ? (replies[i + 2].networkProtocolVersion || 0) : 0
|
||||
},
|
||||
/* block stat counts */
|
||||
blocks: {
|
||||
pending: replies[i + 3],
|
||||
confirmed: replies[i + 4],
|
||||
orphaned: replies[i + 5]
|
||||
},
|
||||
/* show all pending blocks */
|
||||
pending: {
|
||||
blocks: replies[i + 6].sort(sortBlocks),
|
||||
confirms: replies[i + 9]
|
||||
},
|
||||
/* show last 5 found blocks */
|
||||
confirmed: {
|
||||
blocks: replies[i + 7].sort(sortBlocks)
|
||||
blocks: replies[i + 7].sort(sortBlocks).slice(0,5)
|
||||
},
|
||||
payments: replies[i + 10],
|
||||
payments: [],
|
||||
currentRoundShares: replies[i + 8]
|
||||
};
|
||||
for(var j = replies[i + 10].length; j > 0; j--){
|
||||
coinStats.payments.push(JSON.parse(replies[i + 10][j-1]));
|
||||
}
|
||||
/*
|
||||
for (var b in coinStats.confirmed.blocks) {
|
||||
var parms = coinStats.confirmed.blocks[b].split(':');
|
||||
|
@ -460,7 +479,8 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
var shareMultiplier = Math.pow(2, 32) / algos[coinStats.algorithm].multiplier;
|
||||
coinStats.hashrate = shareMultiplier * coinStats.shares / portalConfig.website.stats.hashrateWindow;
|
||||
coinStats.hashrateString = _this.getReadableHashRateString(coinStats.hashrate);
|
||||
var _blocktime = 250;
|
||||
|
||||
var _blocktime = 160;
|
||||
var _networkHashRate = parseFloat(coinStats.poolStats.networkSols) * 1.2;
|
||||
var _myHashRate = (coinStats.hashrate / 1000000) * 2;
|
||||
coinStats.luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||
|
@ -481,7 +501,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
portalStats.algos[algo].hashrate += coinStats.hashrate;
|
||||
portalStats.algos[algo].workers += Object.keys(coinStats.workers).length;
|
||||
|
||||
var _shareTotal = 0;
|
||||
var _shareTotal = parseFloat(0);
|
||||
for (var worker in coinStats.currentRoundShares) {
|
||||
var miner = worker.split(".")[0];
|
||||
if (miner in coinStats.miners) {
|
||||
|
@ -492,10 +512,9 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
}
|
||||
_shareTotal += parseFloat(coinStats.currentRoundShares[worker]);
|
||||
}
|
||||
coinStats.shareCount = Math.round(_shareTotal * 100) / 100;
|
||||
coinStats.shareCount = _shareTotal;
|
||||
|
||||
for (var worker in coinStats.workers) {
|
||||
var _blocktime = 250;
|
||||
var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow;
|
||||
var _wHashRate = (_workerRate / 1000000) * 2;
|
||||
coinStats.workers[worker].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||
|
@ -504,7 +523,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate);
|
||||
}
|
||||
for (var miner in coinStats.miners) {
|
||||
var _blocktime = 250;
|
||||
var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow;
|
||||
var _wHashRate = (_workerRate / 1000000) * 2;
|
||||
coinStats.miners[miner].luckDays = ((_networkHashRate / _wHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3);
|
||||
|
@ -524,13 +542,20 @@ module.exports = function(logger, portalConfig, poolConfigs){
|
|||
var algoStats = portalStats.algos[algo];
|
||||
algoStats.hashrateString = _this.getReadableHashRateString(algoStats.hashrate);
|
||||
});
|
||||
|
||||
// TODO, create stats object and copy elements from portalStats we want to display...
|
||||
var showStats = portalStats;
|
||||
|
||||
|
||||
_this.stats = portalStats;
|
||||
_this.statsString = JSON.stringify(portalStats);
|
||||
_this.statHistory.push(portalStats);
|
||||
|
||||
// save historical hashrate, not entire stats!
|
||||
var saveStats = JSON.parse(JSON.stringify(portalStats));
|
||||
Object.keys(saveStats.pools).forEach(function(pool){
|
||||
delete saveStats.pools[pool].pending;
|
||||
delete saveStats.pools[pool].confirmed;
|
||||
delete saveStats.pools[pool].currentRoundShares;
|
||||
delete saveStats.pools[pool].payments;
|
||||
delete saveStats.pools[pool].miners;
|
||||
});
|
||||
_this.statsString = JSON.stringify(saveStats);
|
||||
_this.statHistory.push(saveStats);
|
||||
|
||||
addStatPoolHistory(portalStats);
|
||||
|
||||
|
|
|
@ -230,7 +230,6 @@ module.exports = function(logger){
|
|||
|
||||
var payout = function(req, res, next){
|
||||
var address = req.params.address || null;
|
||||
|
||||
if (address != null){
|
||||
portalStats.getPayout(address, function(data){
|
||||
res.write(data.toString());
|
||||
|
@ -241,26 +240,20 @@ module.exports = function(logger){
|
|||
next();
|
||||
};
|
||||
|
||||
|
||||
var shares = function(req, res, next){
|
||||
portalStats.getCoins(function(){
|
||||
processTemplates();
|
||||
|
||||
res.end(indexesProcessed['user_shares']);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
var usershares = function(req, res, next){
|
||||
|
||||
var coin = req.params.coin || null;
|
||||
|
||||
if(coin != null){
|
||||
portalStats.getCoinTotals(coin, null, function(){
|
||||
processTemplates();
|
||||
|
||||
res.end(indexesProcessed['user_shares']);
|
||||
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"enabled":false,
|
||||
"coin": "komodo.json",
|
||||
|
||||
"address": "",
|
||||
"_comment_address": "pools komodo address; ex, RSXGTHQSqwcMw1vowKfEE7sQ8fAmv1tmso",
|
||||
|
||||
"zAddress": "",
|
||||
"_comment_zAddress": "shielding not required in komodo, not used",
|
||||
|
||||
"tAddress": "",
|
||||
"_comment_tAddress": "set to same as pools komodo address; ex, RSXGTHQSqwcMw1vowKfEE7sQ8fAmv1tmso",
|
||||
|
||||
"walletInterval": 1,
|
||||
"_comment_walletInterval": "Used to cache komodo coin stats, shielding not performed.",
|
||||
|
||||
"rewardRecipients": {
|
||||
"": 1.0
|
||||
},
|
||||
|
||||
"tlsOptions": {
|
||||
"enabled": false,
|
||||
"serverKey":"",
|
||||
"serverCert":"",
|
||||
"ca":""
|
||||
},
|
||||
|
||||
"paymentProcessing": {
|
||||
"enabled": true,
|
||||
"paymentInterval": 57,
|
||||
"_comment_paymentInterval": "Interval in seconds to check and perform payments.",
|
||||
"minimumPayment": 0.1,
|
||||
"daemon": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 8232,
|
||||
"user": "username",
|
||||
"password": "password"
|
||||
}
|
||||
},
|
||||
|
||||
"ports": {
|
||||
"3857": {
|
||||
"tls":false,
|
||||
"diff": 0.05,
|
||||
"varDiff": {
|
||||
"minDiff": 0.04,
|
||||
"maxDiff": 16,
|
||||
"targetTime": 15,
|
||||
"retargetTime": 60,
|
||||
"variancePercent": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"daemons": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 8232,
|
||||
"user": "username",
|
||||
"password": "password"
|
||||
}
|
||||
],
|
||||
|
||||
"p2p": {
|
||||
"enabled": false,
|
||||
"host": "127.0.0.1",
|
||||
"port": 19333,
|
||||
"disableTransactions": true
|
||||
},
|
||||
|
||||
"mposMode": {
|
||||
"enabled": false,
|
||||
"host": "127.0.0.1",
|
||||
"port": 3306,
|
||||
"user": "me",
|
||||
"password": "mypass",
|
||||
"database": "kmd",
|
||||
"checkPassword": true,
|
||||
"autoCreateWorker": false
|
||||
}
|
||||
|
||||
}
|
|
@ -88,8 +88,8 @@
|
|||
<div class="chartHolder"><svg id="workerHashrate" /></div>
|
||||
<div>
|
||||
<div style="float:right; padding-top: 9px; padding-right: 18px;"><i class="fa fa-cog"></i> Shares: <span id="statsTotalShares">...</span></div>
|
||||
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Bal: <span id="statsTotalBal">...</span> ZEC </div>
|
||||
<div style="padding-top: 9px; padding-left: 18px;"><i class="fa fa-money"></i> Paid: <span id="statsTotalPaid">...</span> ZEC </div>
|
||||
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Bal: <span id="statsTotalBal">...</span> </div>
|
||||
<div style="padding-top: 9px; padding-left: 18px;"><i class="fa fa-money"></i> Paid: <span id="statsTotalPaid">...</span> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue