Browse Source

Better miner privacy

pull/1/head
webworker01 5 years ago
parent
commit
975a86d7b8
  1. 169
      libs/api.js
  2. 32
      libs/filterIterate.js
  3. 74
      libs/stats.js
  4. 20
      libs/website.js

169
libs/api.js

@ -1,6 +1,8 @@
var redis = require('redis');
var async = require('async');
var filterIterate = require('./filterIterate.js');
var stats = require('./stats.js');
module.exports = function(logger, portalConfig, poolConfigs){
@ -15,8 +17,13 @@ module.exports = function(logger, portalConfig, poolConfigs){
switch(req.params.method){
case 'stats':
//Anonymize
let anonymizeJSON = JSON.parse(portalStats.statsString);
for (pool in anonymizeJSON.pools) {
filterIterate(anonymizeJSON.pools[pool].workers, {key: true, prop: ['name']}, 'miner-');
}
res.header('Content-Type', 'application/json');
res.end(portalStats.statsString);
res.end(JSON.stringify(anonymizeJSON));
return;
case 'pool_stats':
res.header('Content-Type', 'application/json');
@ -25,97 +32,105 @@ module.exports = function(logger, portalConfig, poolConfigs){
case 'blocks':
case 'getblocksstats':
portalStats.getBlocks(function(data){
//Anonymize
filterIterate(data, {split:{by:':', index:3}}, 'miner-');
res.header('Content-Type', 'application/json');
res.end(JSON.stringify(data));
res.end(JSON.stringify(data));
});
break;
case 'payments':
var poolBlocks = [];
for(var pool in portalStats.stats.pools) {
filterIterate(portalStats.stats.pools[pool].pending.blocks, {split:{by:':', index:3}}, 'miner-');
for (payment in portalStats.stats.pools[pool].payments) {
filterIterate(portalStats.stats.pools[pool].payments[payment].amounts, {key: true}, 'miner-', );
filterIterate(portalStats.stats.pools[pool].payments[payment].balances, {key: true}, 'miner-', );
filterIterate(portalStats.stats.pools[pool].payments[payment].work, {key: true}, 'miner-', );
}
poolBlocks.push({name: pool, pending: portalStats.stats.pools[pool].pending, payments: portalStats.stats.pools[pool].payments});
}
res.header('Content-Type', 'application/json');
res.end(JSON.stringify(poolBlocks));
return;
case 'worker_stats':
res.header('Content-Type', 'application/json');
if (req.url.indexOf("?")>0) {
var url_parms = req.url.split("?");
if (url_parms.length > 0) {
var history = {};
var workers = {};
var address = url_parms[1] || null;
//res.end(portalStats.getWorkerStats(address));
if (address != null && address.length > 0) {
// make sure it is just the miners address
address = address.split(".")[0];
// get miners balance along with worker balances
portalStats.getBalanceByAddress(address, function(balances) {
// get current round share total
portalStats.getTotalSharesByAddress(address, function(shares) {
var totalHash = parseFloat(0.0);
var totalShares = shares;
var networkSols = 0;
for (var h in portalStats.statHistory) {
for(var pool in portalStats.statHistory[h].pools) {
for(var w in portalStats.statHistory[h].pools[pool].workers){
if (w.startsWith(address)) {
if (history[w] == null) {
history[w] = [];
}
if (portalStats.statHistory[h].pools[pool].workers[w].hashrate) {
history[w].push({time: portalStats.statHistory[h].time, hashrate:portalStats.statHistory[h].pools[pool].workers[w].hashrate});
}
}
}
// order check...
//console.log(portalStats.statHistory[h].time);
}
}
for(var pool in portalStats.stats.pools) {
for(var w in portalStats.stats.pools[pool].workers){
if (w.startsWith(address)) {
workers[w] = portalStats.stats.pools[pool].workers[w];
for (var b in balances.balances) {
if (w == balances.balances[b].worker) {
case 'worker_stats':
res.header('Content-Type', 'application/json');
if (req.url.indexOf("?")>0) {
var url_parms = req.url.split("?");
if (url_parms.length > 0) {
var history = {};
var workers = {};
var address = url_parms[1] || null;
//res.end(portalStats.getWorkerStats(address));
if (address != null && address.length > 0) {
// make sure it is just the miners address
address = address.split(".")[0];
// get miners balance along with worker balances
portalStats.getBalanceByAddress(address, function(balances) {
// get current round share total
portalStats.getTotalSharesByAddress(address, function(shares) {
var totalHash = parseFloat(0.0);
var totalShares = shares;
var networkSols = 0;
for (var h in portalStats.statHistory) {
for(var pool in portalStats.statHistory[h].pools) {
for(var w in portalStats.statHistory[h].pools[pool].workers){
if (w.startsWith(address)) {
if (history[w] == null) {
history[w] = [];
}
if (portalStats.statHistory[h].pools[pool].workers[w].hashrate) {
history[w].push({time: portalStats.statHistory[h].time, hashrate:portalStats.statHistory[h].pools[pool].workers[w].hashrate});
}
}
}
// order check...
//console.log(portalStats.statHistory[h].time);
}
}
for(var pool in portalStats.stats.pools) {
for(var w in portalStats.stats.pools[pool].workers){
if (w.startsWith(address)) {
workers[w] = portalStats.stats.pools[pool].workers[w];
for (var b in balances.balances) {
if (w == balances.balances[b].worker) {
workers[w].paid = balances.balances[b].paid;
workers[w].balance = balances.balances[b].balance;
}
}
workers[w].balance = (workers[w].balance || 0);
workers[w].paid = (workers[w].paid || 0);
totalHash += portalStats.stats.pools[pool].workers[w].hashrate;
networkSols = portalStats.stats.pools[pool].poolStats.networkSols;
}
}
}
res.end(JSON.stringify({miner: address, totalHash: totalHash, totalShares: totalShares, networkSols: networkSols, immature: balances.totalImmature, balance: balances.totalHeld, paid: balances.totalPaid, workers: workers, history: history}));
});
});
} else {
res.end(JSON.stringify({result: "error"}));
}
} else {
res.end(JSON.stringify({result: "error"}));
}
} else {
res.end(JSON.stringify({result: "error"}));
}
}
}
workers[w].balance = (workers[w].balance || 0);
workers[w].paid = (workers[w].paid || 0);
totalHash += portalStats.stats.pools[pool].workers[w].hashrate;
networkSols = portalStats.stats.pools[pool].poolStats.networkSols;
}
}
}
res.end(JSON.stringify({miner: address, totalHash: totalHash, totalShares: totalShares, networkSols: networkSols, immature: balances.totalImmature, balance: balances.totalHeld, paid: balances.totalPaid, workers: workers, history: history}));
});
});
} else {
res.end(JSON.stringify({result: "error"}));
}
} else {
res.end(JSON.stringify({result: "error"}));
}
} else {
res.end(JSON.stringify({result: "error"}));
}
return;
case 'live_stats':
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
var uid = Math.random().toString();
_this.liveStatConnections[uid] = res;
res.flush();
req.on("close", function() {
delete _this.liveStatConnections[uid];
});
return;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
var uid = Math.random().toString();
_this.liveStatConnections[uid] = res;
res.flush();
req.on("close", function() {
delete _this.liveStatConnections[uid];
});
return;
default:
next();
}

32
libs/filterIterate.js

@ -0,0 +1,32 @@
var filterIterate = module.exports = function(iterateThis, replaceTypes, replaceLabel) {
if (typeof iterateThis == 'object') {
let iterateIndex = 1;
for (let item in iterateThis) {
//Replace specified properties
if (typeof replaceTypes.prop !== 'undefined') {
for (let prop of replaceTypes.prop) {
iterateThis[item][prop] = replaceLabel + iterateIndex;
}
}
//Split by a property and use the index indicated in the value
if (typeof replaceTypes.split != 'undefined') {
let splitString = String(iterateThis[item])
let splitItem = splitString.split(replaceTypes.split.by);
splitItem[replaceTypes.split.index] = replaceLabel + iterateIndex;
splitItem = splitItem.join(':');
iterateThis[item] = splitItem;
}
//Replace object keys - last because we are deleting and recreating the element
if (typeof replaceTypes.key !== 'undefined' && replaceTypes.key) {
Object.defineProperty(iterateThis, replaceLabel + iterateIndex, Object.getOwnPropertyDescriptor(iterateThis, item));
delete iterateThis[item];
}
iterateIndex++;
}
}
return iterateThis;
}

74
libs/stats.js

@ -422,38 +422,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
}
//anonymize currentRoundShares
let currentRoundSharesIndex = 0;
for (var worker in replies[i + 8]) {
Object.defineProperty(replies[i+8], 'worker' + currentRoundSharesIndex, Object.getOwnPropertyDescriptor(replies[i+8], worker));
delete replies[i+8][worker];
currentRoundSharesIndex++;
}
//anonymize currentRoundTimes
let currentRoundTimesIndex = 0;
for (var worker in replies[i + 11]) {
Object.defineProperty(replies[i+11], 'worker' + currentRoundTimesIndex, Object.getOwnPropertyDescriptor(replies[i+11], worker));
delete replies[i+11][worker];
currentRoundTimesIndex++;
}
//anonymize confirmed blocks
for (var b=0; b < replies[i + 7].length; b++) {
let blockoutput = replies[i + 7][b].split(':');
blockoutput[3] = coinName + '-miner';
blockoutput = blockoutput.join(':');
replies[i + 7][b] = blockoutput;
}
//anonymize pending blocks
for (var b=0; b < replies[i + 6].length; b++) {
let blockoutput = replies[i + 6][b].split(':');
blockoutput[3] = coinName + '-miner';
blockoutput = blockoutput.join(':');
replies[i + 6][b] = blockoutput;
}
var coinStats = {
name: coinName,
symbol: poolConfigs[coinName].coin.symbol.toUpperCase(),
@ -503,30 +471,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
jsonObj = null;
}
if (jsonObj !== null) {
//Anonymize paid amounts
let paymentIndex = 0;
for (var payment in jsonObj.amounts) {
Object.defineProperty(jsonObj.amounts, 'miner' + paymentIndex, Object.getOwnPropertyDescriptor(jsonObj.amounts, payment));
delete jsonObj.amounts[payment];
paymentIndex++;
}
//Anonymize balances
let balanceIndex = 0;
for (var balance in jsonObj.balances) {
Object.defineProperty(jsonObj.balances, 'miner' + balanceIndex, Object.getOwnPropertyDescriptor(jsonObj.balances, balance));
delete jsonObj.balances[balance];
balanceIndex++;
}
//Anonymize work
let workIndex = 0;
for (var work in jsonObj.work) {
Object.defineProperty(jsonObj.work, 'miner' + workIndex, Object.getOwnPropertyDescriptor(jsonObj.work, work));
delete jsonObj.work[work];
workIndex++;
}
coinStats.payments.push(jsonObj);
}
}
@ -644,24 +588,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
});
//anonymize miners
let minerindex = 0;
for (var miner in coinStats.miners) {
Object.defineProperty(coinStats.miners, 'miner' + minerindex, Object.getOwnPropertyDescriptor(coinStats.miners, miner));
coinStats.miners['miner' + minerindex].name = 'miner' + minerindex;
delete coinStats.miners[miner];
minerindex++;
}
//anonymize workers
let workerindex = 0;
for (var worker in coinStats.workers) {
Object.defineProperty(coinStats.workers, 'worker' + workerindex, Object.getOwnPropertyDescriptor(coinStats.workers, worker));
coinStats.workers['worker' + workerindex].name = 'worker' + workerindex;
delete coinStats.workers[worker];
workerindex++;
}
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);

20
libs/website.js

@ -14,6 +14,8 @@ var compress = require('compression');
//var Stratum = require('stratum-pool');
//var util = require('stratum-pool/lib/util.js');
var filterIterate = require('./filterIterate.js');
var api = require('./api.js');
module.exports = function(logger){
@ -115,8 +117,24 @@ module.exports = function(logger){
portalStats.getGlobalStats(function(){
processTemplates();
//Anonymize
for (pool in portalStats.stats.pools) {
filterIterate(portalStats.stats.pools[pool].confirmed.blocks, {split:{by:':', index:3}}, 'miner-');
filterIterate(portalStats.stats.pools[pool].currentRoundShares, {key: true}, 'miner-');
filterIterate(portalStats.stats.pools[pool].currentRoundTimes, {key: true}, 'miner-');
filterIterate(portalStats.stats.pools[pool].miners, {key: true, prop: ['name']}, 'miner-', );
filterIterate(portalStats.stats.pools[pool].pending.blocks, {split:{by:':', index:3}}, 'miner-');
filterIterate(portalStats.stats.pools[pool].workers, {key: true, prop: ['name']}, 'worker-', );
for (payment in portalStats.stats.pools[pool].payments) {
filterIterate(portalStats.stats.pools[pool].payments[payment].amounts, {key: true}, 'miner-', );
filterIterate(portalStats.stats.pools[pool].payments[payment].balances, {key: true}, 'miner-', );
filterIterate(portalStats.stats.pools[pool].payments[payment].work, {key: true}, 'miner-', );
}
}
var statData = 'data: ' + JSON.stringify(portalStats.stats) + '\n\n';
for (var uid in portalApi.liveStatConnections){
for (var uid in portalApi.liveStatConnections) {
var res = portalApi.liveStatConnections[uid];
res.write(statData);
}

Loading…
Cancel
Save