Updated readme overscrolling text
This commit is contained in:
parent
7be455ebd2
commit
ca27990228
24
README.md
24
README.md
@ -26,6 +26,7 @@ Features
|
|||||||
* Daemon RPC interface
|
* Daemon RPC interface
|
||||||
* Stratum TCP socket server
|
* Stratum TCP socket server
|
||||||
* Block template / job manager
|
* Block template / job manager
|
||||||
|
* P2P to get block notifications as peer node
|
||||||
* Optimized generation transaction building
|
* Optimized generation transaction building
|
||||||
* Connecting to multiple daemons for redundancy
|
* Connecting to multiple daemons for redundancy
|
||||||
* Process share submissions
|
* Process share submissions
|
||||||
@ -42,11 +43,10 @@ Features
|
|||||||
* ✓ __Scrypt-Jane__ (YaCoin, CopperBars, Pennies, Tickets, etc..)
|
* ✓ __Scrypt-Jane__ (YaCoin, CopperBars, Pennies, Tickets, etc..)
|
||||||
* ✓ __Scrypt-N__ (Vertcoin [VTC])
|
* ✓ __Scrypt-N__ (Vertcoin [VTC])
|
||||||
* ✓ __Quark__ (Quarkcoin [QRK])
|
* ✓ __Quark__ (Quarkcoin [QRK])
|
||||||
* ✓ __X11__ (Darkcoin [DRK])
|
* ✓ __X11__ (Darkcoin [DRK], Hirocoin, Limecoin)
|
||||||
|
* ✓ __Keccak__ (Maxcoin [MAX], HelixCoin, CryptoMeth, Galleon, 365coin, Slothcoin, BitcointalkCoin, eCoin, CopperLark)
|
||||||
|
|
||||||
Under development:
|
Under development:
|
||||||
* ✗ *Keccak* (Maxcoin [MAX], HelixCoin, CryptoMeth, eCoin, CopperLark)
|
|
||||||
* ✗ *Skein* (Skeincoin [SKC])
|
* ✗ *Skein* (Skeincoin [SKC])
|
||||||
* ✗ *Groestl* (MyriadCoin [MYR]
|
* ✗ *Groestl* (MyriadCoin [MYR]
|
||||||
* ✗ *Qubit* (QubitCoin [Q2C], MyriadCoin [MYR])
|
* ✗ *Qubit* (QubitCoin [Q2C], MyriadCoin [MYR])
|
||||||
@ -123,6 +123,24 @@ var myCoin = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you are using the `keccak` algorithm there are additional configurations *(The rare `normalHashing` keccak coins
|
||||||
|
such as Copperlark and eCoin don't appear to work yet, byt the popular ones like Maxcoin are)*:
|
||||||
|
```javascript
|
||||||
|
var myCoin = {
|
||||||
|
"name": "eCoin",
|
||||||
|
"symbol": "ECN",
|
||||||
|
"algorithm": "keccak",
|
||||||
|
|
||||||
|
/* This is not required and set to false by default. Some coins such as Copperlark and eCoin
|
||||||
|
require it to be set to true. Maxcoin and most others are false. */
|
||||||
|
"normalHashing": true,
|
||||||
|
/* The rare normalHashing coins also require diff to be manually set here. Do not use for
|
||||||
|
typical keccak coins like Maxcoin. */
|
||||||
|
"diffShift": 32
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Create and start new pool with configuration options and authentication function
|
Create and start new pool with configuration options and authentication function
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|||||||
@ -99,9 +99,16 @@ var algos = module.exports = global.algos = {
|
|||||||
keccak: {
|
keccak: {
|
||||||
shift: 24,
|
shift: 24,
|
||||||
multiplier: Math.pow(2, 24),
|
multiplier: Math.pow(2, 24),
|
||||||
hash: function(){
|
hash: function(coinConfig){
|
||||||
return function(data){
|
if (coinConfig.normalHashing === true) {
|
||||||
return multiHashing.keccak(data);
|
return function (data, nTimeInt) {
|
||||||
|
return multiHashing.keccak(multiHashing.keccak(Buffer.concat([data, new Buffer(nTimeInt.toString(16), 'hex')])));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return function (data) {
|
||||||
|
return multiHashing.keccak(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -139,80 +146,11 @@ var algos = module.exports = global.algos = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Creates a non-truncated max difficulty (diff1) by bitwise right-shifting the max value of a uint256
|
|
||||||
function ShiftMax256Right(shiftRight){
|
|
||||||
|
|
||||||
//Max value uint256 (an array of ones representing 256 enabled bits)
|
|
||||||
var arr256 = Array.apply(null, new Array(256)).map(Number.prototype.valueOf, 1);
|
|
||||||
|
|
||||||
//An array of zero bits for how far the max uint256 is shifted right
|
|
||||||
var arrLeft = Array.apply(null, new Array(shiftRight)).map(Number.prototype.valueOf, 0);
|
|
||||||
|
|
||||||
//Add zero bits to uint256 and remove the bits shifted out
|
|
||||||
arr256 = arrLeft.concat(arr256).slice(0, 256);
|
|
||||||
|
|
||||||
//An array of bytes to convert the bits to, 8 bits in a byte so length will be 32
|
|
||||||
var octets = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < 32; i++){
|
|
||||||
|
|
||||||
octets[i] = 0;
|
|
||||||
|
|
||||||
//The 8 bits for this byte
|
|
||||||
var bits = arr256.slice(i * 8, i * 8 + 8);
|
|
||||||
|
|
||||||
//Bit math to add the bits into a byte
|
|
||||||
for (var f = 0; f < bits.length; f++){
|
|
||||||
var multiplier = Math.pow(2, f);
|
|
||||||
octets[i] += bits[f] * multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Buffer(octets);;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function BufferToCompact(startingBuff){
|
|
||||||
var bigNum = bignum.fromBuffer(startingBuff);
|
|
||||||
var buff = bigNum.toBuffer();
|
|
||||||
|
|
||||||
buff = buff.readUInt8(0) > 0x7f ? Buffer.concat([new Buffer([0x00]), buff]) : buff;
|
|
||||||
|
|
||||||
buff = Buffer.concat([new Buffer([buff.length]), buff]);
|
|
||||||
var compact = buff.slice(0, 4);
|
|
||||||
return compact;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function ConvertBitsToBuff(bitsBuff){
|
|
||||||
var numBytes = bitsBuff.readUInt8(0);
|
|
||||||
var bigBits = bignum.fromBuffer(bitsBuff.slice(1));
|
|
||||||
var target = bigBits.mul(
|
|
||||||
bignum(2).pow(
|
|
||||||
bignum(8).mul(
|
|
||||||
numBytes - 3
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
var resultBuff = target.toBuffer();
|
|
||||||
var buff256 = new Buffer(32);
|
|
||||||
buff256.fill(0);
|
|
||||||
resultBuff.copy(buff256, buff256.length - resultBuff.length);
|
|
||||||
|
|
||||||
return buff256;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var algo in algos){
|
for (var algo in algos){
|
||||||
if (!algos[algo].diff) {
|
if (!algos[algo].diff) {
|
||||||
var nonTruncatedDiff = ShiftMax256Right(algos[algo].shift);
|
algos[algo].nonTruncatedDiff = util.shiftMax256Right(algos[algo].shift);
|
||||||
var compactBits = BufferToCompact(nonTruncatedDiff);
|
algos[algo].bits = util.bufferToCompactBits(algos[algo].nonTruncatedDiff);
|
||||||
var truncatedDiff = ConvertBitsToBuff(compactBits);
|
algos[algo].diff = util.convertBitsToBuff(algos[algo].bits);
|
||||||
|
|
||||||
algos[algo].bits = compactBits;
|
|
||||||
algos[algo].diff = truncatedDiff;
|
|
||||||
algos[algo].nonTruncatedDiff = nonTruncatedDiff;
|
|
||||||
algos[algo].diff = nonTruncatedDiff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,7 @@ var JobCounter = function(){
|
|||||||
* - newBlock(blockTemplate) - When a new block (previously unknown to the JobManager) is added, use this event to broadcast new jobs
|
* - newBlock(blockTemplate) - When a new block (previously unknown to the JobManager) is added, use this event to broadcast new jobs
|
||||||
* - share(shareData, blockHex) - When a worker submits a share. It will have blockHex if a block was found
|
* - share(shareData, blockHex) - When a worker submits a share. It will have blockHex if a block was found
|
||||||
**/
|
**/
|
||||||
var JobManager = module.exports = function JobManager(maxDifficulty, hashDigest, options){
|
var JobManager = module.exports = function JobManager(maxDifficulty, options){
|
||||||
|
|
||||||
|
|
||||||
//private members
|
//private members
|
||||||
@ -65,7 +65,33 @@ var JobManager = module.exports = function JobManager(maxDifficulty, hashDigest,
|
|||||||
|
|
||||||
var lastTransactionUpdateCheck = Date.now();
|
var lastTransactionUpdateCheck = Date.now();
|
||||||
|
|
||||||
var coinbaseHasher = options.coin.algorithm === 'keccak' ? util.sha256 : util.sha256d;
|
var hashDigest = algos[options.coin.algorithm].hash(options.coin);
|
||||||
|
|
||||||
|
var coinbaseHasher = (function(){
|
||||||
|
switch(options.coin.algorithm){
|
||||||
|
case 'keccak':
|
||||||
|
case 'blake':
|
||||||
|
if (options.coin.normalHashing !== true)
|
||||||
|
return util.sha256;
|
||||||
|
default:
|
||||||
|
return util.sha256d;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
var blockHasher = (function(){
|
||||||
|
switch(options.coin.algorithm){
|
||||||
|
case 'keccak':
|
||||||
|
case 'blake':
|
||||||
|
//if (options.coin.normalHashing !== true)
|
||||||
|
return function(d, nTime){
|
||||||
|
util.reverseBuffer(util.sha256d(Buffer.concat([d, new Buffer(nTime, 'hex')])));
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return function(d){
|
||||||
|
util.reverseBuffer(util.sha256d(d));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
//returns true if processed a new block
|
//returns true if processed a new block
|
||||||
this.processTemplate = function(rpcData, publicKey){
|
this.processTemplate = function(rpcData, publicKey){
|
||||||
@ -187,7 +213,7 @@ var JobManager = module.exports = function JobManager(maxDifficulty, hashDigest,
|
|||||||
//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)){
|
||||||
blockHex = job.serializeBlock(headerBuffer, coinbaseBuffer).toString('hex');
|
blockHex = job.serializeBlock(headerBuffer, coinbaseBuffer).toString('hex');
|
||||||
blockHash = util.reverseBuffer(util.sha256d(headerBuffer)).toString('hex');
|
blockHash = blockHasher(headerBuffer, nTime)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (options.emitInvalidBlockHashes)
|
if (options.emitInvalidBlockHashes)
|
||||||
|
|||||||
12
lib/pool.js
12
lib/pool.js
@ -44,10 +44,12 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Which number to use as dividend when converting difficulty to target
|
var diff1 = options.coin.diffShift ?
|
||||||
var maxDifficulty = bignum.fromBuffer(algos[options.coin.algorithm].diff);
|
util.getTruncatedDiff(options.coin.diffShift) :
|
||||||
|
algos[options.coin.algorithm].diff;
|
||||||
|
|
||||||
var hashDigest = algos[options.coin.algorithm].hash(options.coin);
|
//Which number to use as dividend when converting difficulty to target
|
||||||
|
var maxDifficulty = bignum.fromBuffer(diff1);
|
||||||
|
|
||||||
|
|
||||||
this.start = function(){
|
this.start = function(){
|
||||||
@ -115,7 +117,7 @@ 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,
|
||||||
'Network Hash Rate:\t' + (options.initStats.networkHashRate / 1e3).toFixed(6) + ' KH/s',
|
'Network Hash Rate:\t' + util.getReadableHashRateString(options.initStats.networkHashRate),
|
||||||
'Network Difficulty:\t' + _this.jobManager.currentJob.difficulty.toString(),
|
'Network Difficulty:\t' + _this.jobManager.currentJob.difficulty.toString(),
|
||||||
'Listening Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
|
'Listening Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
|
||||||
];
|
];
|
||||||
@ -262,7 +264,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
|
|
||||||
function SetupJobManager(){
|
function SetupJobManager(){
|
||||||
|
|
||||||
_this.jobManager = new jobManager(maxDifficulty, hashDigest, options);
|
_this.jobManager = new jobManager(maxDifficulty, options);
|
||||||
|
|
||||||
_this.jobManager.on('newBlock', function(blockTemplate){
|
_this.jobManager.on('newBlock', function(blockTemplate){
|
||||||
//Check if stratumServer has been initialized yet
|
//Check if stratumServer has been initialized yet
|
||||||
|
|||||||
83
lib/util.js
83
lib/util.js
@ -275,4 +275,87 @@ exports.addressToScript = function(addr){
|
|||||||
var pubkey = decoded.slice(1,-4);
|
var pubkey = decoded.slice(1,-4);
|
||||||
|
|
||||||
return Buffer.concat([new Buffer([0x76, 0xa9, 0x14]), pubkey, new Buffer([0x88, 0xac])]);
|
return Buffer.concat([new Buffer([0x76, 0xa9, 0x14]), pubkey, new Buffer([0x88, 0xac])]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.getReadableHashRateString = function(hashrate){
|
||||||
|
var i = -1;
|
||||||
|
var byteUnits = [ ' KH', ' MH', ' GH', ' TH', ' PH' ];
|
||||||
|
do {
|
||||||
|
hashrate = hashrate / 1024;
|
||||||
|
i++;
|
||||||
|
} while (hashrate > 1024);
|
||||||
|
return hashrate.toFixed(2) + byteUnits[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Creates a non-truncated max difficulty (diff1) by bitwise right-shifting the max value of a uint256
|
||||||
|
exports.shiftMax256Right = function(shiftRight){
|
||||||
|
|
||||||
|
//Max value uint256 (an array of ones representing 256 enabled bits)
|
||||||
|
var arr256 = Array.apply(null, new Array(256)).map(Number.prototype.valueOf, 1);
|
||||||
|
|
||||||
|
//An array of zero bits for how far the max uint256 is shifted right
|
||||||
|
var arrLeft = Array.apply(null, new Array(shiftRight)).map(Number.prototype.valueOf, 0);
|
||||||
|
|
||||||
|
//Add zero bits to uint256 and remove the bits shifted out
|
||||||
|
arr256 = arrLeft.concat(arr256).slice(0, 256);
|
||||||
|
|
||||||
|
//An array of bytes to convert the bits to, 8 bits in a byte so length will be 32
|
||||||
|
var octets = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < 32; i++){
|
||||||
|
|
||||||
|
octets[i] = 0;
|
||||||
|
|
||||||
|
//The 8 bits for this byte
|
||||||
|
var bits = arr256.slice(i * 8, i * 8 + 8);
|
||||||
|
|
||||||
|
//Bit math to add the bits into a byte
|
||||||
|
for (var f = 0; f < bits.length; f++){
|
||||||
|
var multiplier = Math.pow(2, f);
|
||||||
|
octets[i] += bits[f] * multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Buffer(octets);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.bufferToCompactBits = function(startingBuff){
|
||||||
|
var bigNum = bignum.fromBuffer(startingBuff);
|
||||||
|
var buff = bigNum.toBuffer();
|
||||||
|
|
||||||
|
buff = buff.readUInt8(0) > 0x7f ? Buffer.concat([new Buffer([0x00]), buff]) : buff;
|
||||||
|
|
||||||
|
buff = Buffer.concat([new Buffer([buff.length]), buff]);
|
||||||
|
var compact = buff.slice(0, 4);
|
||||||
|
return compact;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.convertBitsToBuff = function(bitsBuff){
|
||||||
|
var numBytes = bitsBuff.readUInt8(0);
|
||||||
|
var bigBits = bignum.fromBuffer(bitsBuff.slice(1));
|
||||||
|
var target = bigBits.mul(
|
||||||
|
bignum(2).pow(
|
||||||
|
bignum(8).mul(
|
||||||
|
numBytes - 3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var resultBuff = target.toBuffer();
|
||||||
|
var buff256 = new Buffer(32);
|
||||||
|
buff256.fill(0);
|
||||||
|
resultBuff.copy(buff256, buff256.length - resultBuff.length);
|
||||||
|
|
||||||
|
return buff256;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getTruncatedDiff = function(shift){
|
||||||
|
return exports.convertBitsToBuff(exports.bufferToCompactBits(exports.shiftMax256Right(shift)));
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user