Added support for multiple ports with their own diffs and vardiff
This commit is contained in:
parent
1716d6d738
commit
eaf8f99d30
45
README.md
45
README.md
@ -83,12 +83,29 @@ var pool = Stratum.createPool({
|
||||
txMessages: false //or true
|
||||
},
|
||||
|
||||
pool: {
|
||||
address: "nhfNedMmQ1Rjb62znwaiJgFhL3f4NQztSp",
|
||||
stratumPort: 3334,
|
||||
//instanceId: 37, //I recommend not to use this option as a crypto-random one will be generated
|
||||
difficulty: 32,
|
||||
blockRefreshInterval: 2000 //milliseconds
|
||||
//instanceId: 37, //Recommend not using this because a crypto-random one will be generated
|
||||
|
||||
|
||||
/* Each pool can have as many ports for your miners to connect to as you wish. Each port can
|
||||
be configured to use its own pool difficulty and variable difficulty settings. varDiff is
|
||||
optional and will only be used for the ports you configure it for. */
|
||||
"ports": {
|
||||
"3032": { //a port for your miners to connect to
|
||||
"diff": 32, //the pool difficulty for this port
|
||||
|
||||
/* Variable difficulty is a feature that will automatically adjust difficulty for
|
||||
individual miners based on their hashrate in order to lower networking overhead */
|
||||
"varDiff": {
|
||||
"minDiff": 8, //minimum difficulty
|
||||
"maxDiff": 512, //network difficulty will be used if it is lower than this
|
||||
"targetTime": 15, //try to get 1 share per this many seconds
|
||||
"retargetTime": 90, //check to see if we should retarget every this many seconds
|
||||
"variancePercent": 30 //allow time to very this % from target without retargeting
|
||||
}
|
||||
},
|
||||
"3256": { //another port for your miners to connect to, this port does not use varDiff
|
||||
"diff": 256 //the pool difficulty
|
||||
}
|
||||
},
|
||||
|
||||
/* Recommended to have at least two daemon instances running in case one drops out-of-sync
|
||||
@ -109,22 +126,6 @@ var pool = Stratum.createPool({
|
||||
}
|
||||
],
|
||||
|
||||
varDiff: {
|
||||
enabled: true, //set to false to disable vardiff functionality
|
||||
minDifficulty: 16, //minimum difficulty. below 16 will cause problems
|
||||
maxDifficulty: 1000, //network difficulty will be used if it is lower than this
|
||||
targetTime: 30, //target time per share (i.e. try to get 1 share per this many seconds)
|
||||
retargetTime: 120, //check to see if we should retarget every this many seconds
|
||||
variancePercent: 20 //allow average time to very this % from target without retarget
|
||||
|
||||
/* By default new difficulties will be sent when a new job is available as stratum
|
||||
protocol (http://mining.bitcoin.cz/stratum-mining) states that new difficulties
|
||||
"will be applied to every next job received from the server." Some miner software
|
||||
will almost immediately apply new difficulties. Set mode to fast for difficulty
|
||||
to be sent immediately. */
|
||||
//mode: 'fast'
|
||||
},
|
||||
|
||||
p2p: {
|
||||
enabled: false,
|
||||
host: "localhost",
|
||||
|
||||
@ -44,7 +44,7 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
||||
bignum.fromBuffer(new Buffer(rpcData.target, 'hex')) :
|
||||
util.bignumFromBits(rpcData.bits);
|
||||
|
||||
this.difficulty = Math.round(maxDifficulty / this.target.toNumber() * 1e8) / 1e8;
|
||||
this.difficulty = (maxDifficulty / this.target.toNumber()) * 65536;
|
||||
|
||||
this.prevHashReversed = util.reverseByteOrder(new Buffer(rpcData.previousblockhash, 'hex')).toString('hex');
|
||||
this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){
|
||||
|
||||
72
lib/pool.js
72
lib/pool.js
@ -69,27 +69,23 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
}
|
||||
|
||||
function SetupVarDiff(){
|
||||
if (!options.varDiff.enabled){
|
||||
emitLog('system', 'VarDiff has been disabled');
|
||||
return;
|
||||
}
|
||||
_this.varDiff = new varDiff(options.varDiff, options.pool.difficulty);
|
||||
_this.varDiff = new varDiff(options.ports);
|
||||
_this.varDiff.on('newDifficulty', function(client, 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 */
|
||||
/* 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);
|
||||
}
|
||||
else{
|
||||
/* We request to set the newDiff @ the next difficulty retarget
|
||||
(which should happen when a new job comes in - AKA BLOCK) */
|
||||
client.enqueueNextDifficulty(newDiff);
|
||||
}
|
||||
}*/
|
||||
|
||||
});
|
||||
emitLog("system", "VarDiff enabled and setup");
|
||||
}
|
||||
@ -133,8 +129,8 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
function SetupJobManager(){
|
||||
_this.jobManager = new jobManager({
|
||||
address : options.address,
|
||||
algorithm : options.coin.algorithm,
|
||||
address : options.pool.address,
|
||||
reward : options.coin.reward,
|
||||
txMessages: options.coin.txMessages
|
||||
});
|
||||
@ -186,7 +182,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
_this.daemon.once('online', function(){
|
||||
async.parallel({
|
||||
addressInfo: function(callback){
|
||||
_this.daemon.cmd('validateaddress', [options.pool.address], function(results){
|
||||
_this.daemon.cmd('validateaddress', [options.address], function(results){
|
||||
|
||||
//Make sure address is valid with each daemon
|
||||
var allValid = results.every(function(result){
|
||||
@ -249,12 +245,6 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
return b.response.blocks - a.response.blocks;
|
||||
})[0].response;
|
||||
|
||||
if (options.varDiff.enabled)
|
||||
_this.varDiff.setNetworkDifficulty(largestHeight.difficulty);
|
||||
|
||||
emitLog('network', 'Current block height at ' + largestHeight.blocks +
|
||||
' with difficulty of ' + largestHeight.difficulty);
|
||||
|
||||
callback(null, largestHeight);
|
||||
|
||||
});
|
||||
@ -289,6 +279,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
emitLog('system','Connected to daemon via RPC');
|
||||
|
||||
|
||||
options.hasSubmitMethod = results.submitMethod;
|
||||
|
||||
if (options.coin.reward === 'POS' && typeof(results.addressInfo.pubkey) == 'undefined') {
|
||||
@ -301,16 +292,17 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
util.script_to_address(results.addressInfo.address) :
|
||||
util.script_to_pubkey(results.addressInfo.pubkey);
|
||||
|
||||
if (options.pool.difficulty > results.miningInfo.difficulty && options.pool.difficulty > 16){
|
||||
var newDiff = results.miningInfo.difficulty > 16 ? results.miningInfo.difficulty : 16;
|
||||
emitWarningLog('system', 'pool difficulty was set higher than network difficulty of ' + results.miningInfo.difficulty);
|
||||
emitWarningLog('system', 'lowering pool diff from ' + options.pool.difficulty + ' to ' + newDiff);
|
||||
var networkDifficulty = Math.round(results.miningInfo.difficulty * 65536);
|
||||
|
||||
options.pool.difficulty = newDiff
|
||||
emitLog('network', 'Current block height at ' + results.miningInfo.blocks +
|
||||
' with difficulty of ' + networkDifficulty);
|
||||
|
||||
if (options.varDiff.enabled)
|
||||
_this.varDiff.setPoolDifficulty(options.pool.difficulty);
|
||||
}
|
||||
Object.keys(options.ports).forEach(function(port){
|
||||
var portDiff = options.ports[port].diff;
|
||||
if (portDiff > networkDifficulty)
|
||||
emitWarningLog('system', 'diff of ' + portDiff + ' on port ' + port + ' was set higher' +
|
||||
'than network difficulty of ' + networkDifficulty);
|
||||
});
|
||||
|
||||
GetBlockTemplate(function(error, result){
|
||||
if (error){
|
||||
@ -337,17 +329,13 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
|
||||
function StartStratumServer(){
|
||||
_this.stratumServer = new stratum.Server({
|
||||
port: options.pool.stratumPort,
|
||||
authorizeFn: authorizeFn
|
||||
});
|
||||
_this.stratumServer = new stratum.Server(options.ports, authorizeFn);
|
||||
_this.stratumServer.on('started', function(){
|
||||
emitLog('system','Stratum server started on port ' + options.pool.stratumPort);
|
||||
emitLog('system','Stratum server started on port(s): ' + Object.keys(options.ports).join(', '));
|
||||
_this.emit('started');
|
||||
}).on('client.connected', function(client){
|
||||
|
||||
if (options.varDiff.enabled)
|
||||
_this.varDiff.manageClient(client);
|
||||
_this.varDiff.manageClient(client);
|
||||
|
||||
client.on('difficultyChanged', function(diff){
|
||||
_this.emit('difficultyUpdate', client.workerName, diff);
|
||||
@ -360,7 +348,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
extraNonce2Size
|
||||
);
|
||||
|
||||
this.sendDifficulty(options.pool.difficulty);
|
||||
this.sendDifficulty(options.ports[client.socket.localPort].diff);
|
||||
this.sendMiningJob(_this.jobManager.currentJob.getJobParams());
|
||||
|
||||
}).on('submit', function(params, resultCallback){
|
||||
@ -393,12 +381,12 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
function SetupBlockPolling(){
|
||||
|
||||
if (typeof options.pool.blockRefreshInterval !== "number" || options.pool.blockRefreshInterval <= 0){
|
||||
if (typeof options.blockRefreshInterval !== "number" || options.blockRefreshInterval <= 0){
|
||||
emitLog('system', 'Block template polling has been disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
var pollingInterval = options.pool.blockRefreshInterval;
|
||||
var pollingInterval = options.blockRefreshInterval;
|
||||
|
||||
setInterval(function () {
|
||||
GetBlockTemplate(function(error, result){});
|
||||
@ -417,7 +405,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
} else {
|
||||
var processedNewBlock = _this.jobManager.processTemplate(result.response, publicKeyBuffer);
|
||||
|
||||
if (processedNewBlock && options.varDiff.enabled)
|
||||
if (processedNewBlock)
|
||||
_this.varDiff.setNetworkDifficulty(_this.jobManager.currentJob.difficulty);
|
||||
|
||||
callback(null, result.response);
|
||||
|
||||
@ -254,12 +254,11 @@ StratumClient.prototype.__proto__ = events.EventEmitter.prototype;
|
||||
* - 'client.disconnected'(StratumClientInstance) - when a miner disconnects. Be aware that the socket cannot be used anymore.
|
||||
* - 'started' - when the server is up and running
|
||||
**/
|
||||
var StratumServer = exports.Server = function StratumServer(options){
|
||||
var StratumServer = exports.Server = function StratumServer(ports, authorizeFn){
|
||||
|
||||
//private members
|
||||
|
||||
var _this = this;
|
||||
var socketServer;
|
||||
var stratumClients = {};
|
||||
var subscriptionCounter = SubscriptionCounter();
|
||||
|
||||
@ -283,12 +282,15 @@ var StratumServer = exports.Server = function StratumServer(options){
|
||||
};
|
||||
|
||||
(function init(){
|
||||
_socketServer = socketServer = net.createServer({allowHalfOpen: true}, function(socket){
|
||||
handleNewClient(socket);
|
||||
});
|
||||
_socketServer.listen(options.port, function(){
|
||||
_this.emit('started');
|
||||
|
||||
Object.keys(ports).forEach(function(port){
|
||||
net.createServer({allowHalfOpen: true}, function(socket){
|
||||
handleNewClient(socket);
|
||||
}).listen(parseInt(port), function(){
|
||||
_this.emit('started');
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
@ -41,26 +41,41 @@ function RingBuffer(maxSize){
|
||||
}
|
||||
|
||||
|
||||
var varDiff = module.exports = function varDiff(options, poolDifficulty){
|
||||
var varDiff = module.exports = function varDiff(ports){
|
||||
var _this = this;
|
||||
|
||||
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;
|
||||
|
||||
var portsCalcInfo = {};
|
||||
|
||||
Object.keys(ports).forEach(function(port){
|
||||
var varDiffOptions = ports[port].varDiff;
|
||||
if (!varDiffOptions) return;
|
||||
|
||||
var variance = varDiffOptions.targetTime * (varDiffOptions.variancePercent / 100);
|
||||
|
||||
portsCalcInfo[parseInt(ports)] = {
|
||||
bufferSize: varDiffOptions.retargetTime / varDiffOptions.targetTime * 4,
|
||||
tMin: varDiffOptions.targetTime - variance,
|
||||
tMax: varDiffOptions.targetTime + variance
|
||||
}
|
||||
});
|
||||
|
||||
this.setNetworkDifficulty = function(diff){
|
||||
networkDifficulty = diff;
|
||||
};
|
||||
this.setPoolDifficulty = function(diff){
|
||||
poolDifficulty = diff;
|
||||
};
|
||||
|
||||
|
||||
this.manageClient = function(client){
|
||||
|
||||
var stratumPort = client.socket.localPort;
|
||||
|
||||
if (!(stratumPort in portsCalcInfo))
|
||||
return;
|
||||
|
||||
var calcInfo = portsCalcInfo[stratumPort];
|
||||
var options = ports[stratumPort];
|
||||
|
||||
var lastTs;
|
||||
var lastRtc;
|
||||
var timeBuffer;
|
||||
@ -72,53 +87,42 @@ var varDiff = module.exports = function varDiff(options, poolDifficulty){
|
||||
if (!lastRtc){
|
||||
lastRtc = ts - options.retargetTime / 2;
|
||||
lastTs = ts;
|
||||
timeBuffer = new RingBuffer(bufferSize);
|
||||
// console.log(bufferSize+ ' first time share vardiff curdiff: '+client.difficulty);
|
||||
timeBuffer = new RingBuffer(calcInfo.bufferSize);
|
||||
return;
|
||||
}
|
||||
|
||||
var sinceLast = ts - lastTs;
|
||||
|
||||
timeBuffer.append(sinceLast);
|
||||
lastTs = ts;
|
||||
|
||||
if ((ts - lastRtc) < options.retargetTime && timeBuffer.size() > 0){
|
||||
// console.log('do not retarget');
|
||||
if ((ts - lastRtc) < options.retargetTime && timeBuffer.size() > 0)
|
||||
return;
|
||||
}
|
||||
|
||||
lastRtc = ts;
|
||||
var avg = timeBuffer.avg();
|
||||
|
||||
|
||||
var ddiff;
|
||||
|
||||
if (avg > tMax && client.difficulty > options.minDifficulty) {
|
||||
if (avg > calcInfo.tMax && client.difficulty > options.minDiff) {
|
||||
ddiff = 0.5;
|
||||
if (ddiff * client.difficulty < options.minDifficulty) {
|
||||
ddiff = options.minDifficulty / client.difficulty;
|
||||
if (ddiff * client.difficulty < options.minDiff) {
|
||||
ddiff = options.minDiff / client.difficulty;
|
||||
}
|
||||
} else if (avg < tMin) {
|
||||
} else if (avg < calcInfo.tMin) {
|
||||
ddiff = 2;
|
||||
|
||||
var diffMax = networkDifficulty < options.maxDifficulty ? networkDifficulty : options.maxDifficulty;
|
||||
var diffMax = options.maxDifficulty;
|
||||
// console.log("Max & network", diffMax, networkDifficulty);
|
||||
var diffMax = networkDifficulty < options.maxDiff ? networkDifficulty : options.maxDiff;
|
||||
var diffMax = options.maxDiff;
|
||||
if (ddiff * client.difficulty > diffMax) {
|
||||
ddiff = diffMax / client.difficulty;
|
||||
}
|
||||
|
||||
// console.log('increasing difficulty, ddiff: ' + ddiff);
|
||||
}
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user