diff --git a/lib/jobManager.js b/lib/jobManager.js index 6b07b75..c47bf6c 100644 --- a/lib/jobManager.js +++ b/lib/jobManager.js @@ -1,4 +1,5 @@ var events = require('events'); +var crypto = require('crypto'); var bignum = require('bignum'); @@ -14,18 +15,17 @@ var blockTemplate = require('./blockTemplate.js'); //Unique extranonce per subscriber -var ExtraNonceCounter = function(){ - var instanceId = 31; +var ExtraNonceCounter = function(configInstanceId){ + + var instanceId = configInstanceId || crypto.randomBytes(4).readUInt32LE(0); var counter = instanceId << 27; - var size = util.packUInt32BE(Math.abs(counter)).length; this.next = function(){ var extraNonce = util.packUInt32BE(Math.abs(counter++)); return extraNonce.toString('hex'); }; - this.size = function(){ - return size; - }; + + this.size = 4; //bytes }; //Unique job per new block template @@ -126,9 +126,9 @@ var JobManager = module.exports = function JobManager(options){ //public members - this.extraNonceCounter = new ExtraNonceCounter(); + this.extraNonceCounter = new ExtraNonceCounter(options.instanceId); this.extraNoncePlaceholder = new Buffer('f000000ff111111f', 'hex'); - this.extraNonce2Size = this.extraNoncePlaceholder.length - this.extraNonceCounter.size(); + this.extraNonce2Size = this.extraNoncePlaceholder.length - this.extraNonceCounter.size; this.currentJob; diff --git a/lib/pool.js b/lib/pool.js index d9909e2..552f8c9 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -50,31 +50,10 @@ var pool = module.exports = function pool(options, authorizeFn){ emitLog('varDiff', 'Difficulty requested for vardiff'); if (_this.stratumServer) RequestDifficulty(function(){}); - }).on('newDifficulty', function(client, newDiff){ - client.sendDifficulty(newDiff); - - /* - Disabled this line of code because it will force the miner - to restart and submit duplicate shares. Stratum-python sends out a - mining.notify but rolls the jobID and sets "clean jobs" to false. - Meaning that the worker will only start on the new work once it - exhausts its current nonce range. But if the miner were to start the - new job, the shares would be invalidated since stratum-python doesn't - insert the new jobID that the share-limiter generated into the jobs - array. Even worse, since the new work is only sent with a new jobID - but with the same extranonce and other job parameters as the last job, - the shares will be duplicate. Perhaps this bug has gone unnoticed - because of how likely it is for a miner to exhaust the nonce range - before new work is sent. - - Here is where stratum-python is bugged: - https://github.com/Crypto-Expert/stratum-mining/blob/master/mining/basic_share_limiter.py#L171-L178 - - So lets only send a new difficulty, and the worker will use it when - it receives a new job from when the block template updates. - */ - //client.sendMiningJob(_this.jobManager.currentJob.getJobParams()); - + }).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); }); emitLog("system", "VarDiff enabled and setup"); } diff --git a/lib/stratum.js b/lib/stratum.js index 1138ce1..19f8482 100644 --- a/lib/stratum.js +++ b/lib/stratum.js @@ -24,7 +24,7 @@ var SubscriptionCounter = function(){ * - submit(data(name, jobID, extraNonce2, ntime, nonce)) **/ var StratumClient = function(options){ - + var pendingDifficulty = null; //private members this.socket = options.socket; @@ -139,9 +139,9 @@ var StratumClient = function(options){ }); } ); - if (_this.lastEmittedDiff !== _this.difficulty){ - _this.lastEmittedDiff = _this.difficulty - _this.emit('difficultyChanged', _this.difficulty); + if (_this.lastEmittedDiff !== _this.currentDifficulty){ + _this.lastEmittedDiff = _this.currentDifficulty + _this.emit('difficultyChanged', _this.currentDifficulty); } } @@ -193,6 +193,18 @@ var StratumClient = function(options){ }); } + this.enqueueNextDifficulty = function(requestedNewDifficulty) { + if (typeof(requestedNewDifficulty) != 'number') { + console.error('[StratumClient.enqueueNextDifficulty] given difficulty parameter is not a number: ['+requestedNewDifficulty+']'); + return false; + } else { + console.log('[StratumClient.enqueueNextDifficulty] next difficulty should be: ['+requestedNewDifficulty+']'); + pendingDifficulty = requestedNewDifficulty; + return true; + } + + + }; //public members @@ -206,26 +218,31 @@ var StratumClient = function(options){ return false; } - if (difficulty !== this.difficulty) { - this.difficulty = difficulty; - sendJson({ - id : null, - method: "mining.set_difficulty", - params: [difficulty]//[512], - }); - return true; - } else { + if (difficulty === this.difficulty) return false; - } + + _this.difficulty = difficulty; + sendJson({ + id : null, + method: "mining.set_difficulty", + params: [difficulty]//[512], + }); + return true; + }; this.sendMiningJob = function(jobParams){ + if (pendingDifficulty !== null){ + _this.sendDifficulty(pendingDifficulty); + pendingDifficulty = null; + } sendJson({ id : null, method: "mining.notify", params: jobParams }); + }; }; StratumClient.prototype.__proto__ = events.EventEmitter.prototype;