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
```javascript
/*
'data' object contains:
job: 4, //stratum work job ID
ip: '71.33.19.37', //ip address of client
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
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
blockHash: '110c0447171ad819dd181216d5d80f41e9218e25d833a2789cb8ba289a52eee4',

View File

@ -2,12 +2,12 @@ var bignum = require('bignum');
var multiHashing = require('multi-hashing');
var util = require('./util.js');
var diff1 = global.diff1 = bignum('00000000ffff0000000000000000000000000000000000000000000000000000', 16);
var algos = module.exports = global.algos = {
sha256: {
//Uncomment diff if you want to use hardcoded truncated diff
//diff: new Buffer('00000000ffff0000000000000000000000000000000000000000000000000000', 'hex'),
shift: 32,
//diff: '00000000ffff0000000000000000000000000000000000000000000000000000',
multiplier: Math.pow(2, 32),
hash: function(){
return function(){
@ -17,8 +17,7 @@ var algos = module.exports = global.algos = {
},
scrypt: {
//Uncomment diff if you want to use hardcoded truncated diff
//diff: new Buffer('0000ffff00000000000000000000000000000000000000000000000000000000', 'hex'),
shift: 20,
//diff: '0000ffff00000000000000000000000000000000000000000000000000000000',
multiplier: Math.pow(2, 16),
hash: function(){
return function(){
@ -27,7 +26,6 @@ var algos = module.exports = global.algos = {
}
},
'scrypt-jane': {
shift: 20,
multiplier: Math.pow(2, 16),
hash: function(coinConfig){
var nTimestamp = coinConfig.chainStartTime || 1367991200;
@ -39,7 +37,6 @@ var algos = module.exports = global.algos = {
}
},
'scrypt-n': {
shift: 20,
multiplier: Math.pow(2, 16),
hash: function(coinConfig){
@ -63,8 +60,7 @@ var algos = module.exports = global.algos = {
}
},
x11: {
shift: 20,
multiplier: Math.pow(2, 32.3),
multiplier: Math.pow(2, 32),
hash: function(){
return function(){
return multiHashing.x11.apply(this, arguments);
@ -72,32 +68,14 @@ var algos = module.exports = global.algos = {
}
},
quark: {
shift: 20,
multipler: Math.pow(2, 16),
multiplier: Math.pow(2, 16),
hash: function(){
return function(){
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: {
shift: 24,
multiplier: Math.pow(2, 24),
hash: function(coinConfig){
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: {
shift: 24,
hash: function(){
@ -148,9 +142,18 @@ var algos = module.exports = global.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].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');
/**
* The BlockTemplate class holds a single job.
* 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;
/*
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.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 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)
if (job.target.ge(headerBigNum)){
@ -219,22 +221,20 @@ var JobManager = module.exports = function JobManager(maxDifficulty, options){
if (options.emitInvalidBlockHashes)
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)
if (headerBigNum.gt(targetUser)){
if (shareDiff < difficulty){
//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;
}
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
if (offPercent > (options.shareVariancePercent || 0)){
return shareError([23, 'low difficulty share of ' + shareDiff.toString()]);
return shareError([23, 'low difficulty share of ' + shareDiff]);
}
else{
_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,
ip: ipAddress,
worker: workerName,
difficulty: difficulty,
shareDiff: shareDiff,
height: job.rpcData.height,
reward: job.rpcData.coinbasevalue,
networkDifficulty : job.difficulty.toString(),
difficulty: difficulty,
shareDiff: shareDiff,
blockDiff : job.difficulty,
blockHash: blockHash,
blockHashInvalid: blockHashInvalid
}, blockHex);
return {result: true, error: null, blockHash: blockHash};

View File

@ -44,12 +44,15 @@ var pool = module.exports = function pool(options, authorizeFn){
throw new Error();
}
var diff1 = options.coin.diffShift ?
util.getTruncatedDiff(options.coin.diffShift) :
algos[options.coin.algorithm].diff;
//var diff1 = options.coin.diffShift ?
// util.getTruncatedDiff(options.coin.diffShift) :
// algos[options.coin.algorithm].diff;
//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(){
@ -86,14 +89,13 @@ var pool = module.exports = function pool(options, authorizeFn){
Object.keys(options.ports).forEach(function(port){
var portDiff = options.ports[port].diff;
if (_this.jobManager.currentJob.difficulty.le(portDiff))
portWarnings.push('port ' + port + ' w/ difficulty ' + portDiff);
if (options.initStats.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
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 ');
emitWarningLog(warnMessage);
}
@ -117,15 +119,14 @@ var pool = module.exports = function pool(options, authorizeFn){
'Detected Reward Type:\t' + options.coin.reward,
'Current Block Height:\t' + _this.jobManager.currentJob.rpcData.height,
'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 Difficulty:\t' + _this.jobManager.currentJob.difficulty.toString(),
'Listening Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
'Stratum Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
];
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'));

View File

@ -4,23 +4,6 @@ var base58 = require('base58-native');
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){
var hash1 = crypto.createHash('sha256');
@ -336,8 +319,12 @@ exports.bufferToCompactBits = function(startingBuff){
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 bigBits = bignum.fromBuffer(bitsBuff.slice(1));
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 buff256 = new Buffer(32);
buff256.fill(0);
resultBuff.copy(buff256, buff256.length - resultBuff.length);
return buff256;
};