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
|
||||
```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',
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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){
|
||||
|
||||
@ -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};
|
||||
|
||||
27
lib/pool.js
27
lib/pool.js
@ -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'));
|
||||
|
||||
33
lib/util.js
33
lib/util.js
@ -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;
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user