Changes in how max difficulty and share validation works. Should be more accurate for scrypt based algos and x11
This commit is contained in:
parent
ca27990228
commit
3db1b47199
@ -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',
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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){
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
27
lib/pool.js
27
lib/pool.js
@ -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'));
|
||||||
|
|||||||
33
lib/util.js
33
lib/util.js
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user