Changes in how max difficulty and share validation works. Should be more accurate for scrypt based algos and x11

This commit is contained in:
Matthew Little 2014-04-17 12:52:52 -06:00
parent ca27990228
commit 3db1b47199
6 changed files with 86 additions and 84 deletions

View File

@ -280,14 +280,16 @@ var pool = Stratum.createPool({
Listen to pool events Listen to pool events
```javascript ```javascript
/* /*
'data' object contains: 'data' object contains:
job: 4, //stratum work job ID job: 4, //stratum work job ID
ip: '71.33.19.37', //ip address of client ip: '71.33.19.37', //ip address of client
worker: 'matt.worker1', //stratum worker name worker: 'matt.worker1', //stratum worker name
difficulty: 64, //stratum client difficulty
reward: 5000000000, //the number of satoshis received as payment for solving this block
height: 443795, //block height height: 443795, //block height
networkDifficulty: 3349 //network difficulty for this block reward: 5000000000, //the number of satoshis received as payment for solving this block
difficulty: 64, //stratum worker difficulty
shareDiff: 78, //actual difficulty of the share
blockDiff: 3349 //difficulty for this block
//AAK the block solution - set if block was found //AAK the block solution - set if block was found
blockHash: '110c0447171ad819dd181216d5d80f41e9218e25d833a2789cb8ba289a52eee4', blockHash: '110c0447171ad819dd181216d5d80f41e9218e25d833a2789cb8ba289a52eee4',

View File

@ -2,12 +2,12 @@ var bignum = require('bignum');
var multiHashing = require('multi-hashing'); var multiHashing = require('multi-hashing');
var util = require('./util.js'); var util = require('./util.js');
var diff1 = global.diff1 = bignum('00000000ffff0000000000000000000000000000000000000000000000000000', 16);
var algos = module.exports = global.algos = { var algos = module.exports = global.algos = {
sha256: { sha256: {
//Uncomment diff if you want to use hardcoded truncated diff //Uncomment diff if you want to use hardcoded truncated diff
//diff: new Buffer('00000000ffff0000000000000000000000000000000000000000000000000000', 'hex'), //diff: '00000000ffff0000000000000000000000000000000000000000000000000000',
shift: 32,
multiplier: Math.pow(2, 32), multiplier: Math.pow(2, 32),
hash: function(){ hash: function(){
return function(){ return function(){
@ -17,8 +17,7 @@ var algos = module.exports = global.algos = {
}, },
scrypt: { scrypt: {
//Uncomment diff if you want to use hardcoded truncated diff //Uncomment diff if you want to use hardcoded truncated diff
//diff: new Buffer('0000ffff00000000000000000000000000000000000000000000000000000000', 'hex'), //diff: '0000ffff00000000000000000000000000000000000000000000000000000000',
shift: 20,
multiplier: Math.pow(2, 16), multiplier: Math.pow(2, 16),
hash: function(){ hash: function(){
return function(){ return function(){
@ -27,7 +26,6 @@ var algos = module.exports = global.algos = {
} }
}, },
'scrypt-jane': { 'scrypt-jane': {
shift: 20,
multiplier: Math.pow(2, 16), multiplier: Math.pow(2, 16),
hash: function(coinConfig){ hash: function(coinConfig){
var nTimestamp = coinConfig.chainStartTime || 1367991200; var nTimestamp = coinConfig.chainStartTime || 1367991200;
@ -39,7 +37,6 @@ var algos = module.exports = global.algos = {
} }
}, },
'scrypt-n': { 'scrypt-n': {
shift: 20,
multiplier: Math.pow(2, 16), multiplier: Math.pow(2, 16),
hash: function(coinConfig){ hash: function(coinConfig){
@ -63,8 +60,7 @@ var algos = module.exports = global.algos = {
} }
}, },
x11: { x11: {
shift: 20, multiplier: Math.pow(2, 32),
multiplier: Math.pow(2, 32.3),
hash: function(){ hash: function(){
return function(){ return function(){
return multiHashing.x11.apply(this, arguments); return multiHashing.x11.apply(this, arguments);
@ -72,32 +68,14 @@ var algos = module.exports = global.algos = {
} }
}, },
quark: { quark: {
shift: 20, multiplier: Math.pow(2, 16),
multipler: Math.pow(2, 16),
hash: function(){ hash: function(){
return function(){ return function(){
return multiHashing.quark.apply(this, arguments); return multiHashing.quark.apply(this, arguments);
} }
} }
}, },
skein: {
shift: 20,
hash: function(){
return function(){
return multiHashing.skein.apply(this, arguments);
}
}
},
bcrypt: {
shift: 11,
hash: function(){
return function(){
return multiHashing.bcrypt.apply(this, arguments);
}
}
},
keccak: { keccak: {
shift: 24,
multiplier: Math.pow(2, 24), multiplier: Math.pow(2, 24),
hash: function(coinConfig){ hash: function(coinConfig){
if (coinConfig.normalHashing === true) { if (coinConfig.normalHashing === true) {
@ -112,6 +90,22 @@ var algos = module.exports = global.algos = {
} }
} }
}, },
skein: {
multiplier: Math.pow(2, 16),
hash: function(){
return function(){
return multiHashing.skein.apply(this, arguments);
}
}
},
bcrypt: {
shift: 11,
hash: function(){
return function(){
return multiHashing.bcrypt.apply(this, arguments);
}
}
},
blake: { blake: {
shift: 24, shift: 24,
hash: function(){ hash: function(){
@ -148,9 +142,18 @@ var algos = module.exports = global.algos = {
for (var algo in algos){ for (var algo in algos){
if (!algos[algo].diff) { if (algos[algo].diff){
algos[algo].maxDiff = bignum(algos[algo].diff, 16);
}
else if (algos[algo].shift){
algos[algo].nonTruncatedDiff = util.shiftMax256Right(algos[algo].shift); algos[algo].nonTruncatedDiff = util.shiftMax256Right(algos[algo].shift);
algos[algo].bits = util.bufferToCompactBits(algos[algo].nonTruncatedDiff); algos[algo].bits = util.bufferToCompactBits(algos[algo].nonTruncatedDiff);
algos[algo].diff = util.convertBitsToBuff(algos[algo].bits); algos[algo].maxDiff = bignum.fromBuffer(util.convertBitsToBuff(algos[algo].bits));
}
else if (algos[algo].multiplier){
algos[algo].maxDiff = diff1.mul(Math.pow(2, 32) / algos[algo].multiplier);
}
else{
algos[algo].maxDiff = diff1;
} }
} }

View File

@ -5,7 +5,6 @@ var transactions = require('./transactions.js');
var util = require('./util.js'); var util = require('./util.js');
/** /**
* The BlockTemplate class holds a single job. * The BlockTemplate class holds a single job.
* and provides several methods to validate and submit it to the daemon coin * and provides several methods to validate and submit it to the daemon coin
@ -36,14 +35,17 @@ var BlockTemplate = module.exports = function BlockTemplate(maxDifficulty, jobId
this.jobId = jobId; this.jobId = jobId;
/*
Use the 'target' field if available, but some daemons only return the 'bits' field
*/
this.target = rpcData.target ?
bignum.fromBuffer(new Buffer(rpcData.target, 'hex')) :
util.bignumFromBits(rpcData.bits);
this.difficulty = maxDifficulty.div(this.target); //Use the 'target' field if available, but some daemons only return the 'bits' field
/*this.target = rpcData.target ?
bignum.fromBuffer(new Buffer(rpcData.target, 'hex')) :
util.bignumFromBits(rpcData.bits);*/
this.target = rpcData.target ?
bignum(rpcData.target, 16) :
util.bignumFromBitsHex(rpcData.bits);
this.difficulty = parseFloat((diff1.toNumber() / this.target.toNumber()).toFixed(9));
this.prevHashReversed = util.reverseByteOrder(new Buffer(rpcData.previousblockhash, 'hex')).toString('hex'); this.prevHashReversed = util.reverseByteOrder(new Buffer(rpcData.previousblockhash, 'hex')).toString('hex');
this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){ this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){

View File

@ -208,7 +208,9 @@ var JobManager = module.exports = function JobManager(maxDifficulty, options){
var blockHash; var blockHash;
var blockHex; var blockHex;
var shareDiff = maxDifficulty.div(headerBigNum); var shareDiff = difficulty < 1 ?
maxDifficulty.toNumber() / headerBigNum.toNumber() :
maxDifficulty.div(headerBigNum).toNumber();
//Check if share is a block candidate (matched network difficulty) //Check if share is a block candidate (matched network difficulty)
if (job.target.ge(headerBigNum)){ if (job.target.ge(headerBigNum)){
@ -219,22 +221,20 @@ var JobManager = module.exports = function JobManager(maxDifficulty, options){
if (options.emitInvalidBlockHashes) if (options.emitInvalidBlockHashes)
blockHashInvalid = util.reverseBuffer(util.sha256d(headerBuffer)).toString('hex'); blockHashInvalid = util.reverseBuffer(util.sha256d(headerBuffer)).toString('hex');
//Difficulty the miner is set to
var targetUser = maxDifficulty.div(difficulty);
//Check if share didn't reached the miner's difficulty) //Check if share didn't reached the miner's difficulty)
if (headerBigNum.gt(targetUser)){ if (shareDiff < difficulty){
//Check if share matched a previous difficulty from before a vardiff retarget //Check if share matched a previous difficulty from before a vardiff retarget
if (previousDifficulty && !headerBigNum.gt(maxDifficulty.div(previousDifficulty))){ if (previousDifficulty && shareDiff >= previousDifficulty){
difficulty = previousDifficulty; difficulty = previousDifficulty;
} }
else{ else{
var offPercent = 100 - (shareDiff.toNumber() / difficulty) * 100; var offPercent = 100 - (shareDiff / difficulty) * 100;
//Check to see if low diff share is within acceptable configured range //Check to see if low diff share is within acceptable configured range
if (offPercent > (options.shareVariancePercent || 0)){ if (offPercent > (options.shareVariancePercent || 0)){
return shareError([23, 'low difficulty share of ' + shareDiff.toString()]); return shareError([23, 'low difficulty share of ' + shareDiff]);
} }
else{ else{
_this.emit('log', 'warning', 'Share accepted a low diff ' + shareDiff + ' off by ' + offPercent.toFixed(2) + '%'); _this.emit('log', 'warning', 'Share accepted a low diff ' + shareDiff + ' off by ' + offPercent.toFixed(2) + '%');
@ -249,14 +249,13 @@ var JobManager = module.exports = function JobManager(maxDifficulty, options){
job: jobId, job: jobId,
ip: ipAddress, ip: ipAddress,
worker: workerName, worker: workerName,
difficulty: difficulty,
shareDiff: shareDiff,
height: job.rpcData.height, height: job.rpcData.height,
reward: job.rpcData.coinbasevalue, reward: job.rpcData.coinbasevalue,
networkDifficulty : job.difficulty.toString(), difficulty: difficulty,
shareDiff: shareDiff,
blockDiff : job.difficulty,
blockHash: blockHash, blockHash: blockHash,
blockHashInvalid: blockHashInvalid blockHashInvalid: blockHashInvalid
}, blockHex); }, blockHex);
return {result: true, error: null, blockHash: blockHash}; return {result: true, error: null, blockHash: blockHash};

View File

@ -44,12 +44,15 @@ var pool = module.exports = function pool(options, authorizeFn){
throw new Error(); throw new Error();
} }
var diff1 = options.coin.diffShift ? //var diff1 = options.coin.diffShift ?
util.getTruncatedDiff(options.coin.diffShift) : // util.getTruncatedDiff(options.coin.diffShift) :
algos[options.coin.algorithm].diff; // algos[options.coin.algorithm].diff;
//Which number to use as dividend when converting difficulty to target //Which number to use as dividend when converting difficulty to target
var maxDifficulty = bignum.fromBuffer(diff1); var maxDifficulty = algos[options.coin.algorithm].maxDiff;
console.log(options.coin.name + ' ' + maxDifficulty.toString(16));
this.start = function(){ this.start = function(){
@ -86,14 +89,13 @@ var pool = module.exports = function pool(options, authorizeFn){
Object.keys(options.ports).forEach(function(port){ Object.keys(options.ports).forEach(function(port){
var portDiff = options.ports[port].diff; var portDiff = options.ports[port].diff;
if (_this.jobManager.currentJob.difficulty.le(portDiff)) if (options.initStats.difficulty < portDiff)
portWarnings.push('port ' + port + ' w/ difficulty ' + portDiff); portWarnings.push('port ' + port + ' w/ diff ' + portDiff);
}); });
//Only let the first fork show synced status or the log wil look flooded with it //Only let the first fork show synced status or the log wil look flooded with it
if (portWarnings.length > 0 && (!process.env.forkId || process.env.forkId === '0')) { if (portWarnings.length > 0 && (!process.env.forkId || process.env.forkId === '0')) {
var warnMessage = 'Network difficulty of ' + _this.jobManager.currentJob.difficulty.toString() + ' is lower than ' var warnMessage = 'Network diff of ' + options.initStats.difficulty + ' is lower than '
+ portWarnings.join(' and '); + portWarnings.join(' and ');
emitWarningLog(warnMessage); emitWarningLog(warnMessage);
} }
@ -117,15 +119,14 @@ var pool = module.exports = function pool(options, authorizeFn){
'Detected Reward Type:\t' + options.coin.reward, 'Detected Reward Type:\t' + options.coin.reward,
'Current Block Height:\t' + _this.jobManager.currentJob.rpcData.height, 'Current Block Height:\t' + _this.jobManager.currentJob.rpcData.height,
'Current Connect Peers:\t' + options.initStats.connections, 'Current Connect Peers:\t' + options.initStats.connections,
'Current Block Diff:\t' + _this.jobManager.currentJob.difficulty,
'Network Difficulty:\t' + options.initStats.difficulty,
'Network Hash Rate:\t' + util.getReadableHashRateString(options.initStats.networkHashRate), 'Network Hash Rate:\t' + util.getReadableHashRateString(options.initStats.networkHashRate),
'Network Difficulty:\t' + _this.jobManager.currentJob.difficulty.toString(), 'Stratum Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
'Listening Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
]; ];
if (typeof options.blockRefreshInterval === "number" && options.blockRefreshInterval > 0) if (typeof options.blockRefreshInterval === "number" && options.blockRefreshInterval > 0)
infoLines.push('Block polling every:\t' + options.blockRefreshInterval + ' ms') infoLines.push('Block polling every:\t' + options.blockRefreshInterval + ' ms');
emitSpecialLog(infoLines.join('\n\t\t\t\t\t\t')); emitSpecialLog(infoLines.join('\n\t\t\t\t\t\t'));

View File

@ -4,23 +4,6 @@ var base58 = require('base58-native');
var bignum = require('bignum'); var bignum = require('bignum');
/*
Used to convert getblocktemplate bits field into target if target is not included.
More info: https://en.bitcoin.it/wiki/Target
*/
exports.bignumFromBits = function(bitsString){
var bitsBuff = new Buffer(bitsString, 'hex');
var numBytes = bitsBuff.readUInt8(0);
var bigBits = bignum.fromBuffer(bitsBuff.slice(1));
var target = bigBits.mul(
bignum(2).pow(
bignum(8).mul(
numBytes - 3
)
)
);
return target;
};
exports.sha256 = function(buffer){ exports.sha256 = function(buffer){
var hash1 = crypto.createHash('sha256'); var hash1 = crypto.createHash('sha256');
@ -336,8 +319,12 @@ exports.bufferToCompactBits = function(startingBuff){
return compact; return compact;
}; };
/*
Used to convert getblocktemplate bits field into target if target is not included.
More info: https://en.bitcoin.it/wiki/Target
*/
exports.convertBitsToBuff = function(bitsBuff){ exports.bignumFromBitsBuffer = function(bitsBuff){
var numBytes = bitsBuff.readUInt8(0); var numBytes = bitsBuff.readUInt8(0);
var bigBits = bignum.fromBuffer(bitsBuff.slice(1)); var bigBits = bignum.fromBuffer(bitsBuff.slice(1));
var target = bigBits.mul( var target = bigBits.mul(
@ -347,12 +334,20 @@ exports.convertBitsToBuff = function(bitsBuff){
) )
) )
); );
return target;
};
exports.bignumFromBitsHex = function(bitsString){
var bitsBuff = new Buffer(bitsString, 'hex');
return exports.bignumFromBitsBuffer(bitsBuff);
};
exports.convertBitsToBuff = function(bitsBuff){
var target = exports.bignumFromBitsBuffer(bitsBuff);
var resultBuff = target.toBuffer(); var resultBuff = target.toBuffer();
var buff256 = new Buffer(32); var buff256 = new Buffer(32);
buff256.fill(0); buff256.fill(0);
resultBuff.copy(buff256, buff256.length - resultBuff.length); resultBuff.copy(buff256, buff256.length - resultBuff.length);
return buff256; return buff256;
}; };