node-stratum-pool/lib/varDiff.js
2014-01-16 10:05:44 -07:00

130 lines
3.5 KiB
JavaScript

var events = require('events');
/*
Vardiff ported from stratum-mining share-limiter
https://github.com/ahmedbodi/stratum-mining/blob/master/mining/basic_share_limiter.py
*/
function RingBuffer(maxSize){
var data = [];
var cursor = 0;
var isFull = false;
this.append = function(x){
if (isFull){
data[cursor] = x;
cursor = (cursor + 1) % maxSize;
}
else{
data.push(x);
cursor++;
if (data.length === maxSize){
cursor = 0;
isFull = true;
}
}
};
this.avg = function(){
var total = data.reduce(function(a, b){
return a + b;
});
return total / (isFull ? maxSize : cursor);
};
this.size = function(){
return isFull ? maxSize : cursor;
};
this.clear = function(){
data = [];
cursor = 0;
isFull = false;
};
}
var varDiff = module.exports = function varDiff(options, poolDifficulty){
var _this = this;
this.setNetworkDifficulty = function(diff){
networkDifficulty = diff;
};
if (!options.enabled){
return;
}
var networkDifficulty;
var bufferSize = options.retargetTime / options.targetTime * 4;
var variance = options.targetTime * (options.variancePercent / 100);
var tMin = options.targetTime - variance;
var tMax = options.targetTime + variance;
setInterval(function(){
_this.emit('difficultyRequest');
}, options.daemonDiffUpdateFrequency * 1000);
this.manageClient = function(client){
var lastTs;
var lastRtc;
var timeBuffer;
client.on('submit', function(){
var ts = Date.now() / 1000;
if (!lastRtc){
lastRtc = ts - options.retargetTime / 2;
lastTs = ts;
timeBuffer = new RingBuffer(bufferSize);
console.log('first time share vardiff');
return;
}
timeBuffer.append(ts - lastTs);
lastTs = ts;
if ((ts - lastRtc) < options.retargetTime && timeBuffer.size() > 0){
console.log('do not retarget');
return;
}
lastRtc = ts;
var avg = timeBuffer.avg();
if (avg < 1)
avg = 1;
var ddiff = (client.difficulty * (options.targetTime / avg)) - client.difficulty;
if (avg > tMax && client.difficulty > options.minDifficulty){
if (ddiff > -1)
ddiff = -1;
if (ddiff + client.difficulty < poolDifficulty)
ddiff = options.minDifficulty - client.difficulty;
}
else if (avg < tMin){
if (ddiff < 1)
ddiff = 1;
var diffMax = networkDifficulty < options.maxDifficulty ? networkDifficulty : options.maxDifficulty;
if (ddiff + client.difficulty > diffMax)
ddiff = diffMax - client.difficulty;
}
else{
console.log('hashrate in range ' + JSON.stringify({ddiff: ddiff, avg: avg}) );
return;
}
var newDiff = client.difficulty * ddiff;
timeBuffer.clear();
console.log('sending new difficutly ' + newDiff);
_this.emit('newDifficulty', client, newDiff);
});
};
};
varDiff.prototype.__proto__ = events.EventEmitter.prototype;