Stuff for miners switch

This commit is contained in:
Andrea 2014-03-14 19:11:52 +00:00
parent 7cf448d1e2
commit a4f302b526
5 changed files with 181 additions and 209 deletions

View File

@ -45,92 +45,6 @@ function DaemonInterface(options){
} }
function performHttpRequest(instance, jsonData, callback){
var options = {
hostname: (typeof(instance.host) === 'undefined' ? 'localhost' : instance.host),
port : instance.port,
method : 'POST',
auth : instance.user + ':' + instance.password,
headers : {
'Content-Length': jsonData.length
}
};
var req = http.request(options, function(res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function(){
var dataJson;
var parsingError;
try{
dataJson = JSON.parse(data);
}
catch(e){
if (res.statusCode === 401){
parsingError = 'unauthorized';
_this.emit('error', 'Invalid RPC username or password');
}
else{
parsingError = e;
_this.emit('error', 'could not parse rpc data with request of: ' + jsonData +
' on instance ' + instance.index + ' data: ' + data);
}
}
if (typeof(dataJson) !== 'undefined'){
callback(dataJson.error, dataJson);
}
else
callback(parsingError);
});
});
req.on('error', function(e) {
if (e.code === 'ECONNREFUSED')
callback({type: 'offline', message: e.message}, null);
else
callback({type: 'request error', message: e.message}, null);
});
req.end(jsonData);
};
//Performs a batch JSON-RPC command - only uses the first configured rpc daemon
/* First argument must have:
[
[ methodName, [params] ],
[ methodName, [params] ]
]
*/
function batchCmd(cmdArray, callback){
var requestJson = [];
for (var i = 0; i < cmdArray.length; i++){
requestJson.push({
method: cmdArray[i][0],
params: cmdArray[i][1],
id: Date.now() + Math.floor(Math.random() * 10) + i
});
}
var serializedRequest = JSON.stringify(requestJson);
performHttpRequest(instances[0], serializedRequest, function(error, result){
callback(error, result);
}, 'fuck');
}
/* Sends a JSON RPC (http://json-rpc.org/wiki/specification) command to every configured daemon. /* Sends a JSON RPC (http://json-rpc.org/wiki/specification) command to every configured daemon.
The callback function is fired once with the result from each daemon unless streamResults is The callback function is fired once with the result from each daemon unless streamResults is
set to true. */ set to true. */
@ -141,7 +55,7 @@ function DaemonInterface(options){
async.each(instances, function(instance, eachCallback){ async.each(instances, function(instance, eachCallback){
var itemFinished = function(error, result){ var itemFinished = function(error, result){
var returnObj = {error: error, response: result.result, instance: instance}; var returnObj = {error: error, response: result, instance: instance};
if (streamResults) callback(returnObj); if (streamResults) callback(returnObj);
else results.push(returnObj); else results.push(returnObj);
eachCallback(); eachCallback();
@ -149,15 +63,55 @@ function DaemonInterface(options){
}; };
var requestJson = JSON.stringify({ var requestJson = JSON.stringify({
id: Date.now() + Math.floor(Math.random() * 10),
method: method, method: method,
params: params, params: params
id: Date.now() + Math.floor(Math.random() * 10)
}); });
performHttpRequest(instance, requestJson, function(error, result){ var options = {
itemFinished(error, result); hostname: (typeof(instance.host) === 'undefined' ? 'localhost' : instance.host),
port : instance.port,
method : 'POST',
auth : instance.user + ':' + instance.password,
headers : {
'Content-Length': requestJson.length
}
};
var req = http.request(options, function(res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function(){
var dataJson;
var parsingError;
try{
dataJson = JSON.parse(data);
}
catch(e){
parsingError = e;
_this.emit('error', 'could not parse rpc data from method: ' + method +
' on instance ' + instance.index + ' data: ' + data);
}
if (typeof(dataJson) !== 'undefined')
itemFinished(dataJson.error, dataJson.result);
else
itemFinished(parsingError);
});
}); });
req.on('error', function(e) {
if (e.code === 'ECONNREFUSED')
itemFinished({type: 'offline', message: e.message}, null);
else
itemFinished({type: 'request error', message: e.message}, null);
});
req.end(requestJson);
}, function(){ }, function(){
if (!streamResults){ if (!streamResults){
@ -173,7 +127,6 @@ function DaemonInterface(options){
this.init = init; this.init = init;
this.isOnline = isOnline; this.isOnline = isOnline;
this.cmd = cmd; this.cmd = cmd;
this.batchCmd = batchCmd;
} }
DaemonInterface.prototype.__proto__ = events.EventEmitter.prototype; DaemonInterface.prototype.__proto__ = events.EventEmitter.prototype;

View File

@ -270,7 +270,6 @@ var JobManager = module.exports = function JobManager(options){
worker: workerName, worker: workerName,
difficulty: difficulty, difficulty: difficulty,
height: job.rpcData.height, height: job.rpcData.height,
reward: job.rpcData.coinbasevalue,
networkDifficulty: job.difficulty, networkDifficulty: job.difficulty,
solution: blockHash solution: blockHash
}, blockHex); }, blockHex);

View File

@ -28,7 +28,7 @@ var pool = module.exports = function pool(options, authorizeFn){
var _this = this; var _this = this;
var publicKeyBuffer; var publicKeyBuffer;
var blockPollingIntervalId;
var emitLog = function(key, text) { _this.emit('log', 'debug' , key, text); }; var emitLog = function(key, text) { _this.emit('log', 'debug' , key, text); };
@ -39,7 +39,14 @@ var pool = module.exports = function pool(options, authorizeFn){
emitLog('system', 'Starting pool for ' + options.coin.name + ' [' + options.coin.symbol.toUpperCase() + ']'); emitLog('system', 'Starting pool for ' + options.coin.name + ' [' + options.coin.symbol.toUpperCase() + ']');
SetupJobManager(); SetupJobManager();
SetupVarDiff(); SetupVarDiff();
SetupDaemonInterface(); SetupDaemonInterface(function (err, newDaemon) {
if (!err) {
_this.daemon = newDaemon;
SetupBlockPolling();
StartStratumServer();
SetupPeer();
}
});
SetupApi(); SetupApi();
}; };
@ -69,23 +76,8 @@ var pool = module.exports = function pool(options, authorizeFn){
} }
function SetupVarDiff(){ function SetupVarDiff(){
_this.varDiff = new varDiff(options.ports); Object.keys(options.ports).forEach(function(port) {
_this.varDiff.on('newDifficulty', function(client, newDiff) { _this.setVarDiff(port, new varDiff(port, options.ports[port]));
/* We request to set the newDiff @ the next difficulty retarget
(which should happen when a new job comes in - AKA BLOCK) */
client.enqueueNextDifficulty(newDiff);
/*if (options.varDiff.mode === 'fast'){
//Send new difficulty, then force miner to use new diff by resending the
//current job parameters but with the "clean jobs" flag set to false
//so the miner doesn't restart work and submit duplicate shares
client.sendDifficulty(newDiff);
var job = _this.jobManager.currentJob.getJobParams();
job[8] = false;
client.sendMiningJob(job);
}*/
}); });
} }
@ -163,9 +155,8 @@ var pool = module.exports = function pool(options, authorizeFn){
emitShare(); emitShare();
else{ else{
SubmitBlock(blockHex, function(){ SubmitBlock(blockHex, function(){
CheckBlockAccepted(shareData.solution, function(isAccepted, tx){ CheckBlockAccepted(shareData.solution, function(isAccepted){
isValidBlock = isAccepted; isValidBlock = isAccepted;
shareData.tx = tx;
emitShare(); emitShare();
}); });
}); });
@ -176,13 +167,13 @@ var pool = module.exports = function pool(options, authorizeFn){
} }
function SetupDaemonInterface(){ function SetupDaemonInterface(cback){
emitLog('system', 'Connecting to daemon(s)'); emitLog('system', 'Connecting to daemon(s)');
_this.daemon = new daemon.interface(options.daemons); var newDaemon = new daemon.interface(options.daemons);
_this.daemon.once('online', function(){ newDaemon.once('online', function(){
async.parallel({ async.parallel({
addressInfo: function(callback){ addressInfo: function(callback){
_this.daemon.cmd('validateaddress', [options.address], function(results){ newDaemon.cmd('validateaddress', [options.address], function(results){
//Make sure address is valid with each daemon //Make sure address is valid with each daemon
var allValid = results.every(function(result){ var allValid = results.every(function(result){
@ -205,7 +196,7 @@ var pool = module.exports = function pool(options, authorizeFn){
}); });
}, },
miningInfo: function(callback){ miningInfo: function(callback){
_this.daemon.cmd('getmininginfo', [], function(results){ newDaemon.cmd('getmininginfo', [], function(results){
// Print which network each daemon is running on // Print which network each daemon is running on
@ -252,7 +243,7 @@ var pool = module.exports = function pool(options, authorizeFn){
submitMethod: function(callback){ submitMethod: function(callback){
/* This checks to see whether the daemon uses submitblock /* This checks to see whether the daemon uses submitblock
or getblocktemplate for submitting new blocks */ or getblocktemplate for submitting new blocks */
_this.daemon.cmd('submitblock', [], function(results){ newDaemon.cmd('submitblock', [], function(results){
var couldNotDetectMethod = results.every(function(result){ var couldNotDetectMethod = results.every(function(result){
if (result.error && result.error.message === 'Method not found'){ if (result.error && result.error.message === 'Method not found'){
callback(null, false); callback(null, false);
@ -274,6 +265,7 @@ var pool = module.exports = function pool(options, authorizeFn){
}, function(err, results){ }, function(err, results){
if (err){ if (err){
emitErrorLog('system', 'Could not start pool, ' + JSON.stringify(err)); emitErrorLog('system', 'Could not start pool, ' + JSON.stringify(err));
cback(err);
return; return;
} }
@ -285,6 +277,7 @@ var pool = module.exports = function pool(options, authorizeFn){
if (options.coin.reward === 'POS' && typeof(results.addressInfo.pubkey) == 'undefined') { if (options.coin.reward === 'POS' && typeof(results.addressInfo.pubkey) == 'undefined') {
// address provided is not of the wallet. // address provided is not of the wallet.
emitErrorLog('system', 'The address provided is not from the daemon wallet.'); emitErrorLog('system', 'The address provided is not from the daemon wallet.');
cback(err);
return; return;
} else { } else {
@ -304,15 +297,13 @@ var pool = module.exports = function pool(options, authorizeFn){
'than network difficulty of ' + networkDifficulty); 'than network difficulty of ' + networkDifficulty);
}); });
GetBlockTemplate(function(error, result){ GetBlockTemplate(newDaemon, function(error, result){
if (error){ if (error) {
console.error(error); console.error(error);
emitErrorLog('system', 'Error with getblocktemplate on initializing'); emitErrorLog('system', 'Error with getblocktemplate on initializing');
} cback(error);
else{ } else {
SetupBlockPolling(); cback(null, newDaemon); // finish!
StartStratumServer();
SetupPeer();
} }
}); });
} }
@ -324,7 +315,7 @@ var pool = module.exports = function pool(options, authorizeFn){
emitErrorLog('system', message); emitErrorLog('system', message);
}); });
_this.daemon.init(); newDaemon.init();
} }
@ -334,8 +325,10 @@ var pool = module.exports = function pool(options, authorizeFn){
emitLog('system','Stratum server started on port(s): ' + Object.keys(options.ports).join(', ')); emitLog('system','Stratum server started on port(s): ' + Object.keys(options.ports).join(', '));
_this.emit('started'); _this.emit('started');
}).on('client.connected', function(client){ }).on('client.connected', function(client){
if (typeof(_this.varDiff[client.socket.localPort]) !== 'undefined') {
_this.varDiff.manageClient(client); _this.varDiff[client.socket.localPort].manageClient(client);
}
client.on('difficultyChanged', function(diff){ client.on('difficultyChanged', function(diff){
_this.emit('difficultyUpdate', client.workerName, diff); _this.emit('difficultyUpdate', client.workerName, diff);
@ -348,7 +341,12 @@ var pool = module.exports = function pool(options, authorizeFn){
extraNonce2Size extraNonce2Size
); );
this.sendDifficulty(options.ports[client.socket.localPort].diff); if (typeof(options.ports[client.socket.localPort]) !== 'undefined' && options.ports[client.socket.localPort].diff) {
this.sendDifficulty(options.ports[client.socket.localPort].diff);
} else {
this.sendDifficulty(8);
}
this.sendMiningJob(_this.jobManager.currentJob.getJobParams()); this.sendMiningJob(_this.jobManager.currentJob.getJobParams());
}).on('submit', function(params, resultCallback){ }).on('submit', function(params, resultCallback){
@ -391,14 +389,18 @@ var pool = module.exports = function pool(options, authorizeFn){
var pollingInterval = options.blockRefreshInterval; var pollingInterval = options.blockRefreshInterval;
setInterval(function () { blockPollingIntervalId = setInterval(function () {
GetBlockTemplate(function(error, result){}); GetBlockTemplate(function(error, result){});
}, pollingInterval); }, pollingInterval);
emitLog('system', 'Block polling every ' + pollingInterval + ' milliseconds'); emitLog('system', 'Block polling every ' + pollingInterval + ' milliseconds');
} }
function GetBlockTemplate(callback){ function GetBlockTemplate(daemonObj, callback){
_this.daemon.cmd('getblocktemplate', if (typeof(callback) === 'undefined') {
callback = daemonObj;
daemonObj = _this.daemon;
}
daemonObj.cmd('getblocktemplate',
[{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}], [{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}],
function(result){ function(result){
if (result.error){ if (result.error){
@ -408,8 +410,12 @@ var pool = module.exports = function pool(options, authorizeFn){
} else { } else {
var processedNewBlock = _this.jobManager.processTemplate(result.response, publicKeyBuffer); var processedNewBlock = _this.jobManager.processTemplate(result.response, publicKeyBuffer);
if (processedNewBlock) if (processedNewBlock) {
_this.varDiff.setNetworkDifficulty(_this.jobManager.currentJob.difficulty); Object.keys(_this.varDiff).forEach(function(port){
_this.varDiff[port].setNetworkDifficulty(_this.jobManager.currentJob.difficulty);
});
}
callback(null, result.response); callback(null, result.response);
callback = function(){}; callback = function(){};
@ -422,13 +428,9 @@ var pool = module.exports = function pool(options, authorizeFn){
_this.daemon.cmd('getblock', _this.daemon.cmd('getblock',
[blockHash], [blockHash],
function(results){ function(results){
if (results.filter(function(result){return result.response &&
var validResults = results.filter(function(result){ (result.response.hash === blockHash)}).length >= 1){
return result.response && (result.response.hash === blockHash) callback(true);
});
if (validResults.length >= 1){
callback(true, validResults[0].response.tx[0]);
} }
else{ else{
callback(false); callback(false);
@ -442,8 +444,9 @@ var pool = module.exports = function pool(options, authorizeFn){
* This method is being called from the blockNotify so that when a new block is discovered by the daemon * This method is being called from the blockNotify so that when a new block is discovered by the daemon
* We can inform our miners about the newly found block * We can inform our miners about the newly found block
**/ **/
this.processBlockNotify = function(blockHash){ this.processBlockNotify = function(blockHash) {
if (blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){
if (typeof(_this.jobManager.currentJob) !== 'undefined' && blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){
GetBlockTemplate(function(error, result){ GetBlockTemplate(function(error, result){
if (error) if (error)
emitErrorLog('system', 'Block notify error getting block template for ' + options.coin.name); emitErrorLog('system', 'Block notify error getting block template for ' + options.coin.name);
@ -451,6 +454,8 @@ var pool = module.exports = function pool(options, authorizeFn){
} }
}; };
this.relinquishMiners = function(filterFn, resultCback) { this.relinquishMiners = function(filterFn, resultCback) {
var origStratumClients = this.stratumServer.getStratumClients(); var origStratumClients = this.stratumServer.getStratumClients();
@ -485,7 +490,40 @@ var pool = module.exports = function pool(options, authorizeFn){
miners.forEach(function (clientObj) { miners.forEach(function (clientObj) {
_this.stratumServer.manuallyAddStratumClient(clientObj); _this.stratumServer.manuallyAddStratumClient(clientObj);
}); });
} _this.stratumServer.broadcastMiningJobs(_this.jobManager.currentJob.getJobParams());
};
this.getStratumServer = function() {
return _this.stratumServer;
};
this.setVarDiff = function(port, varDiffInstance) {
if (typeof(_this.varDiff) === 'undefined') {
_this.varDiff = {};
}
if (typeof(_this.varDiff[port]) != 'undefined' ) {
_this.varDiff[port].removeAllListeners();
}
_this.varDiff[port] = varDiffInstance;
_this.varDiff[port].on('newDifficulty', function(client, newDiff) {
/* We request to set the newDiff @ the next difficulty retarget
(which should happen when a new job comes in - AKA BLOCK) */
client.enqueueNextDifficulty(newDiff);
/*if (options.varDiff.mode === 'fast'){
//Send new difficulty, then force miner to use new diff by resending the
//current job parameters but with the "clean jobs" flag set to false
//so the miner doesn't restart work and submit duplicate shares
client.sendDifficulty(newDiff);
var job = _this.jobManager.currentJob.getJobParams();
job[8] = false;
client.sendMiningJob(job);
}*/
});
};
}; };
pool.prototype.__proto__ = events.EventEmitter.prototype; pool.prototype.__proto__ = events.EventEmitter.prototype;

View File

@ -271,9 +271,8 @@ var StratumClient = function(options){
}; };
this.manuallyInitClient = function (username, password) { this.manuallyAuthClient = function (username, password) {
handleAuthorize({id: 1, params: [username, password]}, false /*do not reply to miner*/); handleAuthorize({id: 1, params: [username, password]}, false /*do not reply to miner*/);
handleSubscribe({id: 2});
} }
}; };
StratumClient.prototype.__proto__ = events.EventEmitter.prototype; StratumClient.prototype.__proto__ = events.EventEmitter.prototype;
@ -292,16 +291,14 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
//private members //private members
var socketTimeout = connectionTimeout * 1000; var socketTimeout = connectionTimeout * 1000;
var bannedMS = banning.time * 1000; var bannedMS = banning.time * 1000;
var _this = this; var _this = this;
var stratumClients = {}; var stratumClients = {};
var subscriptionCounter = SubscriptionCounter(); var subscriptionCounter = SubscriptionCounter();
var rebroadcastTimeout; var bannedIPs = {};
var bannedIPs = {};
//Interval to look through bannedIPs for old bans and remove them in order to prevent a memory leak //Interval to look through bannedIPs for old bans and remove them in order to prevent a memory leak
var purgeOldBans = !banning.enabled ? null : setInterval(function(){ var purgeOldBans = !banning.enabled ? null : setInterval(function(){
@ -312,7 +309,20 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
} }
}, 1000 * banning.purgeInterval); }, 1000 * banning.purgeInterval);
var handleNewClient = function (socket) { this.handleNewClient = function (socket) {
if (banning.enabled && socket.remoteAddress in bannedIPs){
var bannedTime = bannedIPs[socket.remoteAddress];
if ((Date.now() - bannedTime) < bannedMS){
socket.end();
return null;
}
else {
delete bannedIPs[socket.remoteAddress];
}
}
// If we're here the client was not banned.
socket.setKeepAlive(true); socket.setKeepAlive(true);
var subscriptionId = subscriptionCounter.next(); var subscriptionId = subscriptionCounter.next();
var client = new StratumClient( var client = new StratumClient(
@ -327,6 +337,7 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
stratumClients[subscriptionId] = client; stratumClients[subscriptionId] = client;
_this.emit('client.connected', client); _this.emit('client.connected', client);
client.on('socketDisconnect', function() { client.on('socketDisconnect', function() {
console.log("Socket disconnected for: "+client);
_this.removeStratumClientBySubId(subscriptionId); _this.removeStratumClientBySubId(subscriptionId);
_this.emit('client.disconnected', client); _this.emit('client.disconnected', client);
}).on('ban', function(ipAddress){ }).on('ban', function(ipAddress){
@ -337,28 +348,11 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
(function init(){ (function init(){
var serversStarted = 0;
Object.keys(ports).forEach(function(port){ Object.keys(ports).forEach(function(port){
net.createServer({allowHalfOpen: false}, function(socket){ net .createServer({allowHalfOpen: true}, function(socket) { _this.handleNewClient(socket); } )
.listen(parseInt(port), function(){
if (banning.enabled && socket.remoteAddress in bannedIPs){
var bannedTime = bannedIPs[socket.remoteAddress];
if ((Date.now() - bannedTime) < bannedMS){
socket.end();
return;
}
else{
delete bannedIPs[socket.remoteAddress];
}
}
handleNewClient(socket);
}).listen(parseInt(port), function(){
serversStarted++;
if (serversStarted === Object.keys(ports).length)
_this.emit('started'); _this.emit('started');
}); });
}); });
})(); })();
@ -379,15 +373,6 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
client.sendMiningJob(jobParams); client.sendMiningJob(jobParams);
} }
} }
/* Some miners will consider the pool dead if it doesn't receive a job at least every 30 seconds.
So every time broadcast jobs, we set a timeout to rebroadcast in 30 seconds unless cleared. */
clearTimeout(rebroadcastTimeout);
rebroadcastTimeout = setTimeout(function(){
var resendParams = jobParams;
resendParams[8] = false;
_this.broadcastMiningJobs(resendParams);
}, 30000);
}; };
this.getStratumClients = function () { this.getStratumClients = function () {
@ -399,8 +384,10 @@ var StratumServer = exports.Server = function StratumServer(ports, connectionTim
}; };
this.manuallyAddStratumClient = function(clientObj) { this.manuallyAddStratumClient = function(clientObj) {
var subId = handleNewClient(clientObj.socket); var subId = _this.handleNewClient(clientObj.socket);
stratumClients[subscriptionId].manuallyInit(clientObj.workerName, clientObj.workerPass); if (subId != null) { // not banned!
stratumClients[subId].manuallyAuthClient(clientObj.workerName, clientObj.workerPass);
}
} }
}; };

View File

@ -41,25 +41,21 @@ function RingBuffer(maxSize){
} }
var varDiff = module.exports = function varDiff(ports){ var varDiff = module.exports = function varDiff(port, varDiffOptions){
var _this = this; var _this = this;
var networkDifficulty; var networkDifficulty;
var portsCalcInfo = {}; var bufferSize, tMin, tMax;
Object.keys(ports).forEach(function(port){ if (!varDiffOptions) return;
var varDiffOptions = ports[port].varDiff;
if (!varDiffOptions) return;
var variance = varDiffOptions.targetTime * (varDiffOptions.variancePercent / 100); var variance = varDiffOptions.targetTime * (varDiffOptions.variancePercent / 100);
portsCalcInfo[parseInt(port)] = {
bufferSize: varDiffOptions.retargetTime / varDiffOptions.targetTime * 4, bufferSize = varDiffOptions.retargetTime / varDiffOptions.targetTime * 4;
tMin: varDiffOptions.targetTime - variance, tMin = varDiffOptions.targetTime - variance;
tMax: varDiffOptions.targetTime + variance tMax = varDiffOptions.targetTime + variance;
}
});
this.setNetworkDifficulty = function(diff){ this.setNetworkDifficulty = function(diff){
networkDifficulty = diff; networkDifficulty = diff;
@ -70,11 +66,10 @@ var varDiff = module.exports = function varDiff(ports){
var stratumPort = client.socket.localPort; var stratumPort = client.socket.localPort;
if (!(stratumPort in portsCalcInfo)) if (stratumPort != port) {
return; console.error("Handling a client which is not of this vardiff?");
}
var calcInfo = portsCalcInfo[stratumPort]; var options = varDiffOptions
var options = ports[stratumPort].varDiff;
var lastTs; var lastTs;
var lastRtc; var lastRtc;
@ -87,7 +82,7 @@ var varDiff = module.exports = function varDiff(ports){
if (!lastRtc){ if (!lastRtc){
lastRtc = ts - options.retargetTime / 2; lastRtc = ts - options.retargetTime / 2;
lastTs = ts; lastTs = ts;
timeBuffer = new RingBuffer(calcInfo.bufferSize); timeBuffer = new RingBuffer(bufferSize);
return; return;
} }
@ -103,12 +98,12 @@ var varDiff = module.exports = function varDiff(ports){
var avg = timeBuffer.avg(); var avg = timeBuffer.avg();
var ddiff; var ddiff;
if (avg > calcInfo.tMax && client.difficulty > options.minDiff) { if (avg > tMax && client.difficulty > options.minDiff) {
ddiff = 0.5; ddiff = 0.5;
if (ddiff * client.difficulty < options.minDiff) { if (ddiff * client.difficulty < options.minDiff) {
ddiff = options.minDiff / client.difficulty; ddiff = options.minDiff / client.difficulty;
} }
} else if (avg < calcInfo.tMin) { } else if (avg < tMin) {
ddiff = 2; ddiff = 2;
var diffMax = networkDifficulty < options.maxDiff ? networkDifficulty : options.maxDiff; var diffMax = networkDifficulty < options.maxDiff ? networkDifficulty : options.maxDiff;