stratum-pool-sugarchain
Version:
High performance Sugarchain Stratum poolserver in Node.js
377 lines (309 loc) • 9.71 kB
JavaScript
var crypto = require('crypto');
var base58 = require('base58-native');
var bignum = require('bignum');
exports.addressFromEx = function(exAddress, ripdm160Key){
try {
var versionByte = exports.getVersionByte(exAddress);
var addrBase = Buffer.concat([versionByte, new Buffer(ripdm160Key, 'hex')]);
var checksum = exports.sha256d(addrBase).slice(0, 4);
var address = Buffer.concat([addrBase, checksum]);
return base58.encode(address);
}
catch(e){
return null;
}
};
exports.getVersionByte = function(addr){
var versionByte = base58.decode(addr).slice(0, 1);
return versionByte;
};
exports.sha256 = function(buffer){
var hash1 = crypto.createHash('sha256');
hash1.update(buffer);
return hash1.digest();
};
exports.sha256d = function(buffer){
return exports.sha256(exports.sha256(buffer));
};
exports.reverseBuffer = function(buff){
var reversed = new Buffer(buff.length);
for (var i = buff.length - 1; i >= 0; i--)
reversed[buff.length - i - 1] = buff[i];
return reversed;
};
exports.reverseHex = function(hex){
return exports.reverseBuffer(new Buffer(hex, 'hex')).toString('hex');
};
exports.reverseByteOrder = function(buff){
for (var i = 0; i < 8; i++) buff.writeUInt32LE(buff.readUInt32BE(i * 4), i * 4);
return exports.reverseBuffer(buff);
};
exports.uint256BufferFromHash = function(hex){
var fromHex = new Buffer(hex, 'hex');
if (fromHex.length != 32){
var empty = new Buffer(32);
empty.fill(0);
fromHex.copy(empty);
fromHex = empty;
}
return exports.reverseBuffer(fromHex);
};
exports.hexFromReversedBuffer = function(buffer){
return exports.reverseBuffer(buffer).toString('hex');
};
/*
Defined in bitcoin protocol here:
https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer
*/
exports.varIntBuffer = function(n){
if (n < 0xfd)
return new Buffer([n]);
else if (n <= 0xffff){
var buff = new Buffer(3);
buff[0] = 0xfd;
buff.writeUInt16LE(n, 1);
return buff;
}
else if (n <= 0xffffffff){
var buff = new Buffer(5);
buff[0] = 0xfe;
buff.writeUInt32LE(n, 1);
return buff;
}
else{
var buff = new Buffer(9);
buff[0] = 0xff;
exports.packUInt16LE(n).copy(buff, 1);
return buff;
}
};
exports.varStringBuffer = function(string){
var strBuff = new Buffer(string);
return Buffer.concat([exports.varIntBuffer(strBuff.length), strBuff]);
};
/*
"serialized CScript" formatting as defined here:
https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki#specification
Used to format height and date when putting into script signature:
https://en.bitcoin.it/wiki/Script
*/
exports.serializeNumber = function(n){
/* Old version that is bugged
if (n < 0xfd){
var buff = new Buffer(2);
buff[0] = 0x1;
buff.writeUInt8(n, 1);
return buff;
}
else if (n <= 0xffff){
var buff = new Buffer(4);
buff[0] = 0x3;
buff.writeUInt16LE(n, 1);
return buff;
}
else if (n <= 0xffffffff){
var buff = new Buffer(5);
buff[0] = 0x4;
buff.writeUInt32LE(n, 1);
return buff;
}
else{
return Buffer.concat([new Buffer([0x9]), binpack.packUInt64(n, 'little')]);
}*/
//New version from TheSeven
if (n >= 1 && n <= 16) return new Buffer([0x50 + n]);
var l = 1;
var buff = new Buffer(9);
while (n > 0x7f)
{
buff.writeUInt8(n & 0xff, l++);
n >>= 8;
}
buff.writeUInt8(l, 0);
buff.writeUInt8(n, l++);
return buff.slice(0, l);
};
/*
Used for serializing strings used in script signature
*/
exports.serializeString = function(s){
if (s.length < 253)
return Buffer.concat([
new Buffer([s.length]),
new Buffer(s)
]);
else if (s.length < 0x10000)
return Buffer.concat([
new Buffer([253]),
exports.packUInt16LE(s.length),
new Buffer(s)
]);
else if (s.length < 0x100000000)
return Buffer.concat([
new Buffer([254]),
exports.packUInt32LE(s.length),
new Buffer(s)
]);
else
return Buffer.concat([
new Buffer([255]),
exports.packUInt16LE(s.length),
new Buffer(s)
]);
};
exports.packUInt16LE = function(num){
var buff = new Buffer(2);
buff.writeUInt16LE(num, 0);
return buff;
};
exports.packInt32LE = function(num){
var buff = new Buffer(4);
buff.writeInt32LE(num, 0);
return buff;
};
exports.packInt32BE = function(num){
var buff = new Buffer(4);
buff.writeInt32BE(num, 0);
return buff;
};
exports.packUInt32LE = function(num){
var buff = new Buffer(4);
buff.writeUInt32LE(num, 0);
return buff;
};
exports.packUInt32BE = function(num){
var buff = new Buffer(4);
buff.writeUInt32BE(num, 0);
return buff;
};
exports.packInt64LE = function(num){
var buff = new Buffer(8);
buff.writeUInt32LE(num % Math.pow(2, 32), 0);
buff.writeUInt32LE(Math.floor(num / Math.pow(2, 32)), 4);
return buff;
};
/*
An exact copy of python's range feature. Written by Tadeck:
http://stackoverflow.com/a/8273091
*/
exports.range = function(start, stop, step){
if (typeof stop === 'undefined'){
stop = start;
start = 0;
}
if (typeof step === 'undefined'){
step = 1;
}
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)){
return [];
}
var result = [];
for (var i = start; step > 0 ? i < stop : i > stop; i += step){
result.push(i);
}
return result;
};
/*
For POS coins - used to format wallet address for use in generation transaction's output
*/
exports.pubkeyToScript = function(key){
if (key.length !== 66) {
console.error('Invalid pubkey: ' + key);
throw new Error();
}
var pubkey = new Buffer(35);
pubkey[0] = 0x21;
pubkey[34] = 0xac;
new Buffer(key, 'hex').copy(pubkey, 1);
return pubkey;
};
exports.miningKeyToScript = function(key){
var keyBuffer = new Buffer(key, 'hex');
return Buffer.concat([new Buffer([0x76, 0xa9, 0x14]), keyBuffer, new Buffer([0x88, 0xac])]);
};
/*
For POW coins - used to format wallet address for use in generation transaction's output
*/
exports.addressToScript = function(addr){
var decoded = base58.decode(addr);
if (decoded.length != 25){
console.error('invalid address length for ' + addr);
throw new Error();
}
if (!decoded){
console.error('base58 decode failed for ' + addr);
throw new Error();
}
var pubkey = decoded.slice(1,-4);
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;
};
/*
Used to convert getblocktemplate bits field into target if target is not included.
More info: https://en.bitcoin.it/wiki/Target
*/
exports.bignumFromBitsBuffer = 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
)
)
);
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;
};
exports.getTruncatedDiff = function(shift){
return exports.convertBitsToBuff(exports.bufferToCompactBits(exports.shiftMax256Right(shift)));
};