From 897dadbf11c3159d9cf630e5dbd31a3dfc0a3245 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 19 Feb 2014 13:46:17 -0700 Subject: [PATCH] Fixed duplicate shares on vardiff difficulty update. Added more comments. --- lib/jobManager.js | 26 +++++++++++++++++++++----- lib/pool.js | 20 +++++++++++++++++++- lib/transactions.js | 20 ++++++++++++++------ 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/lib/jobManager.js b/lib/jobManager.js index 4a151e5..a364b11 100644 --- a/lib/jobManager.js +++ b/lib/jobManager.js @@ -16,10 +16,10 @@ var blockTemplate = require('./blockTemplate.js'); var ExtraNonceCounter = function(){ var instanceId = 31; var counter = instanceId << 27; - var size = util.packUInt32BE(counter).length; //binpack.packUInt32(counter, 'big').length; + var size = util.packUInt32BE(counter).length; this.next = function(){ - var extraNonce = util.packUInt32BE(counter++);//binpack.packUInt32(counter++, 'big'); + var extraNonce = util.packUInt32BE(counter++); return extraNonce.toString('hex'); }; this.size = function(){ @@ -54,6 +54,7 @@ var JobManager = module.exports = function JobManager(options){ var _this = this; var jobCounter = new JobCounter(); + //var jobs = {}; /** * It only checks if the blockTemplate is already in our jobs list. @@ -68,8 +69,19 @@ var JobManager = module.exports = function JobManager(options){ } else { return false; } + + /*var newBlock = true; + for(var job in jobs){ + if (jobs[job].rpcData.previousblockhash === prevBlockHash) { + newBlock = false; + } + } + return newBlock;*/ + } + + //Which number to use as dividend when converting difficulty to target var diffDividend = (function(){ switch(options.algorithm){ case 'sha256': @@ -82,6 +94,8 @@ var JobManager = module.exports = function JobManager(options){ } })(); + + //On initialization lets figure out which hashing algorithm to use var hashDigest = (function(){ switch(options.algorithm){ case 'sha256': @@ -103,7 +117,6 @@ var JobManager = module.exports = function JobManager(options){ } })(); - //public members @@ -125,6 +138,8 @@ var JobManager = module.exports = function JobManager(options){ options.txMessages ); + //jobs[tmpBlockTemplate.jobId] = tmpBlockTemplate; + this.currentJob = tmpBlockTemplate; _this.emit('newBlock', tmpBlockTemplate); } @@ -132,7 +147,6 @@ var JobManager = module.exports = function JobManager(options){ this.processShare = function(jobId, difficulty, extraNonce1, extraNonce2, nTime, nonce, ipAddress, workerName){ - var shareError = function(error){ _this.emit('share', { job: jobId, @@ -150,7 +164,9 @@ var JobManager = module.exports = function JobManager(options){ return shareError([20, 'incorrect size of extranonce2']); var job = this.currentJob; - if ( job.jobId != jobId ) { + //var job = jobs[jobId]; + + if (typeof job === 'undefined' || job.jobId != jobId ) { return shareError([21, 'job not found']); } diff --git a/lib/pool.js b/lib/pool.js index 0b92208..300b23d 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -52,7 +52,25 @@ var pool = module.exports = function pool(options, authorizeFn){ RequestDifficulty(function(){}); }).on('newDifficulty', function(client, newDiff){ client.sendDifficulty(newDiff); - client.sendMiningJob(_this.jobManager.currentJob.getJobParams()); + + /* + Disabled this line of code as it will because it will force the miner + to restart and submit duplicate shares. The 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. Also, since the new work is only sent with a new jobID but with + the same extranonce as the last job, the shares will be duplicate + anyway. 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. + + So lets only send a new difficulty, and the worker will use it when + it receives a new job when the block template updates. + */ + //client.sendMiningJob(_this.jobManager.currentJob.getJobParams()); + }); emitLog("system", "VarDiff enabled and setup"); } diff --git a/lib/transactions.js b/lib/transactions.js index d8dbe5d..e3d4f95 100644 --- a/lib/transactions.js +++ b/lib/transactions.js @@ -118,10 +118,7 @@ var Generation = exports.Generation = function Generation(rpcData, publicKey, ex /* This function creates the generation transaction that accepts the reward for -successfully mining a new block. Creating this function required tons of trial -and error and reversing existing pool server code. I went to write a good comment -describing how it works in detail but at this point I don't even know.. - +successfully mining a new block. For some (probably outdated and incorrect) documentation about whats kinda going on here, see: https://en.bitcoin.it/wiki/Protocol_specification#tx */ @@ -139,6 +136,11 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r var txInPrevOutIndex = Math.pow(2, 32) - 1; var txInSequence = 0; + //Only required for POS coins + var txTimestamp = reward === 'POS' ? + util.packUInt32LE(rpcData.curtime) : new Buffer([]); + + //For coins that support/require transaction comments var txComment = txMessages === true ? util.serializeString('https://github.com/zone117x/node-stratum') : new Buffer([]); @@ -153,10 +155,9 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r var scriptSigPart2 = util.serializeString('/nodeStratum/'); - var p1 = Buffer.concat([ util.packUInt32LE(txVersion), - reward === 'POS' ? util.packUInt32LE(rpcData.curtime) : new Buffer([]), + txTimestamp, util.varIntBuffer(txInputsCount), //transaction input @@ -166,6 +167,13 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r scriptSigPart1 ]); + + /* + The generation transaction must be split at the extranonce (which located in the transaction input + scriptSig). Miners send us unique extranonces that we use to join the two parts in attempt to create + a valid share and/or block. + */ + var p2 = Buffer.concat([ scriptSigPart2, util.packUInt32LE(txInSequence),