updated
This commit is contained in:
parent
b37f4f974b
commit
7a21abacc4
@ -12,9 +12,9 @@ Features (mostly untested)
|
|||||||
* Stratum TCP socket server
|
* Stratum TCP socket server
|
||||||
* Block template / job manager
|
* Block template / job manager
|
||||||
* Optimized generation transaction building
|
* Optimized generation transaction building
|
||||||
|
* Process share submissions
|
||||||
|
|
||||||
#### To do
|
#### To do
|
||||||
* Handle share submissions
|
|
||||||
* Payment processing module
|
* Payment processing module
|
||||||
* Support more algos (scrypt, scrypt-jane, quark)
|
* Support more algos (scrypt, scrypt-jane, quark)
|
||||||
* Port [scrypt hash](https://github.com/Tydus/litecoin_scrypt) to node module
|
* Port [scrypt hash](https://github.com/Tydus/litecoin_scrypt) to node module
|
||||||
|
|||||||
@ -10,6 +10,8 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
|||||||
|
|
||||||
//private members
|
//private members
|
||||||
|
|
||||||
|
var submits = [];
|
||||||
|
|
||||||
function getMerkleHashes(steps){
|
function getMerkleHashes(steps){
|
||||||
return steps.map(function(step){
|
return steps.map(function(step){
|
||||||
return util.reverseBuffer(step).toString('hex');
|
return util.reverseBuffer(step).toString('hex');
|
||||||
@ -28,6 +30,11 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
|||||||
|
|
||||||
this.rpcData = rpcData;
|
this.rpcData = rpcData;
|
||||||
this.jobId = jobId;
|
this.jobId = jobId;
|
||||||
|
this.target = util.bignumFromBits(rpcData.bits);
|
||||||
|
this.previousHashBuffer = util.reverseHex(rpcData.previousblockhash);
|
||||||
|
this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){
|
||||||
|
return new Buffer(tx.data, 'hex');
|
||||||
|
}));
|
||||||
this.merkleTree = new merkleTree(getTransactionBuffers(rpcData.transactions));
|
this.merkleTree = new merkleTree(getTransactionBuffers(rpcData.transactions));
|
||||||
this.merkleBranch = getMerkleHashes(this.merkleTree.steps);
|
this.merkleBranch = getMerkleHashes(this.merkleTree.steps);
|
||||||
this.generationTransaction = new transactions.Generation(
|
this.generationTransaction = new transactions.Generation(
|
||||||
@ -37,11 +44,49 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
|||||||
extraNoncePlaceholder
|
extraNoncePlaceholder
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.serializeCoinbase = function(extraNonce1, extraNonce2){
|
||||||
|
return Buffer.concat([
|
||||||
|
this.generationTransaction.coinbase[0],
|
||||||
|
extraNonce1,
|
||||||
|
extraNonce2,
|
||||||
|
this.generationTransaction.coinbase[1]
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeHeader = function(merkleRootBuffer, nTimeBuffer, nonceBuffer){
|
||||||
|
return Buffer.concat([
|
||||||
|
binpack.packInt32(rpcData.version, 'big'),
|
||||||
|
this.previousHashBuffer,
|
||||||
|
merkleRootBuffer,
|
||||||
|
nTimeBuffer,
|
||||||
|
new Buffer(this.rpcData.bits, 'hex'),
|
||||||
|
nonceBuffer
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeBlock = function(header, coinbase){
|
||||||
|
return Buffer.concat([
|
||||||
|
header,
|
||||||
|
util.varIntBuffer(this.rpcData.transaction.length + 1),
|
||||||
|
coinbase,
|
||||||
|
this.transactionData
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.registerSubmit = function(extraNonce1Buffer, extraNonce2, nTime, nonce){
|
||||||
|
var submission = extraNonce1Buffer.toString('hex') + extraNonce2 + nTime + nonce;
|
||||||
|
if (submits.indexOf(submission) === -1){
|
||||||
|
submits.push(submission);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
this.getJobParams = function(){
|
this.getJobParams = function(){
|
||||||
if (!this.jobParams){
|
if (!this.jobParams){
|
||||||
this.jobParams = [
|
this.jobParams = [
|
||||||
this.jobId,
|
this.jobId,
|
||||||
util.reverseHex(this.rpcData.previousblockhash),
|
this.previousHashBuffer,
|
||||||
this.generationTransaction.coinbase[0].toString('hex'),
|
this.generationTransaction.coinbase[0].toString('hex'),
|
||||||
this.generationTransaction.coinbase[1].toString('hex'),
|
this.generationTransaction.coinbase[1].toString('hex'),
|
||||||
this.merkleBranch,
|
this.merkleBranch,
|
||||||
|
|||||||
@ -67,10 +67,67 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
jobs[this.currentJob.jobId] = this.currentJob;
|
jobs[this.currentJob.jobId] = this.currentJob;
|
||||||
CheckNewIfNewBlock(this.currentJob);
|
CheckNewIfNewBlock(this.currentJob);
|
||||||
};
|
};
|
||||||
this.processShare = function(jobId, difficulty, extraNonce1, extraNonce2, nTime, nonce){
|
this.processShare = function(jobId, difficulty, extraNonce1Buffer, extraNonce2, nTime, nonce){
|
||||||
|
|
||||||
var submitTime = Date.now() / 1000 | 0;
|
var submitTime = Date.now() / 1000 | 0;
|
||||||
|
|
||||||
|
if (extraNonce2.length / 2 !== _this.extraNonce2Size)
|
||||||
|
return {error: [20, 'incorrect size of extranonce2', null]};
|
||||||
|
|
||||||
|
|
||||||
|
var job = jobs[jobId];
|
||||||
|
if (!job)
|
||||||
|
return {error: [21, 'job not found', null]};
|
||||||
|
|
||||||
|
|
||||||
|
if (nTime.length !== 8)
|
||||||
|
return {error: [20, 'incorrect size of ntime']};
|
||||||
|
|
||||||
|
|
||||||
|
var nTimeInt = parseInt(nTime, 16);
|
||||||
|
if (nTimeInt < job.rpcData.curtime || nTime > submitTime + 7200)
|
||||||
|
return {error: [20, 'ntime out of range', null]};
|
||||||
|
|
||||||
|
|
||||||
|
if (nonce.length !== 8)
|
||||||
|
return {error: [20, 'incorrect size of nonce']};
|
||||||
|
|
||||||
|
|
||||||
|
if (!job.registerSubmit(extraNonce1Buffer, extraNonce2, nTime, nonce))
|
||||||
|
return {error: [22, 'duplicate share', null]};
|
||||||
|
|
||||||
|
|
||||||
|
var extraNonce2Buffer = new Buffer(extraNonce2, 'hex');
|
||||||
|
var nTimeBuffer = new Buffer(nTime, 'hex');
|
||||||
|
var nonceBuffer = new Buffer(nonce, 'hex');
|
||||||
|
|
||||||
|
|
||||||
|
var coinbaseBuffer = job.serializeCoinbase(extraNonce1Buffer, extraNonce2Buffer);
|
||||||
|
var coinbaseHash = util.doublesha(coinbaseBuffer);
|
||||||
|
|
||||||
|
|
||||||
|
var merkleRootBuffer = job.merkleTree.withFirst(coinbaseHash);
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
merkleRootBuffer.writeUInt32LE(merkleRootBuffer.readUInt32BE(i * 4), i * 4);
|
||||||
|
|
||||||
|
|
||||||
|
var headerBuffer = job.serializeHeader(merkleRootBuffer, nTimeBuffer, nonceBuffer);
|
||||||
|
for (var i = 0; i < 20; i++) headerBuffer.writeUInt32LE(headerBuffer.readUInt32BE(i * 4), i * 4);
|
||||||
|
var headerHash = util.doublesha(headerBuffer);
|
||||||
|
var headerBigNum = bignum.fromBuffer(headerHash);
|
||||||
|
|
||||||
|
|
||||||
|
var targetUser = bignum.fromBuffer(
|
||||||
|
new Buffer('00000000ffff0000000000000000000000000000000000000000000000000000', 'hex')
|
||||||
|
).div(difficulty);
|
||||||
|
if (headerBigNum.gt(targetUser))
|
||||||
|
return {error: [23, 'low difficulty share', null]};
|
||||||
|
|
||||||
|
|
||||||
|
if (headerBigNum.gt(job.target)){
|
||||||
|
_this.emit('blockFound', job.serializeBlock(headerBuffer, coinbaseBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
9
main.js
9
main.js
@ -1,7 +1,16 @@
|
|||||||
var net = require('net');
|
var net = require('net');
|
||||||
|
|
||||||
|
var bignum = require('bignum');
|
||||||
|
|
||||||
var pool = require('./pool.js');
|
var pool = require('./pool.js');
|
||||||
|
|
||||||
|
var fff = "03be78733329d27a63d6ca058a1e3e1048d90e945c2ee985f4bc9042da280a4b";
|
||||||
|
var ff = new Buffer(fff, 'hex');
|
||||||
|
var nn = bignum.fromBuffer(ff);
|
||||||
|
var aa = nn.toBuffer();
|
||||||
|
console.log(aa.toString('hex'));
|
||||||
|
|
||||||
|
|
||||||
function Coin(options){
|
function Coin(options){
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|||||||
3
pool.js
3
pool.js
@ -60,7 +60,7 @@ var pool = module.exports = function pool(coin){
|
|||||||
}, function(err, results){
|
}, function(err, results){
|
||||||
if (err) return;
|
if (err) return;
|
||||||
|
|
||||||
//console.log(results);
|
|
||||||
|
|
||||||
publicKeyBuffer = coin.options.reward === 'POW' ?
|
publicKeyBuffer = coin.options.reward === 'POW' ?
|
||||||
util.script_to_address(results.addressInfo.address) :
|
util.script_to_address(results.addressInfo.address) :
|
||||||
@ -68,6 +68,7 @@ var pool = module.exports = function pool(coin){
|
|||||||
|
|
||||||
_this.jobManager.newTemplate(results.rpcTemplate, publicKeyBuffer);
|
_this.jobManager.newTemplate(results.rpcTemplate, publicKeyBuffer);
|
||||||
|
|
||||||
|
console.log(results.rpcTemplate);
|
||||||
console.log(_this.jobManager.currentJob.getJobParams());
|
console.log(_this.jobManager.currentJob.getJobParams());
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user