This commit is contained in:
Matthew Little 2014-01-07 03:23:56 -05:00
parent b37f4f974b
commit 7a21abacc4
5 changed files with 116 additions and 4 deletions

View File

@ -12,9 +12,9 @@ Features (mostly untested)
* Stratum TCP socket server
* Block template / job manager
* Optimized generation transaction building
* Process share submissions
#### To do
* Handle share submissions
* Payment processing module
* Support more algos (scrypt, scrypt-jane, quark)
* Port [scrypt hash](https://github.com/Tydus/litecoin_scrypt) to node module

View File

@ -10,6 +10,8 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
//private members
var submits = [];
function getMerkleHashes(steps){
return steps.map(function(step){
return util.reverseBuffer(step).toString('hex');
@ -28,6 +30,11 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
this.rpcData = rpcData;
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.merkleBranch = getMerkleHashes(this.merkleTree.steps);
this.generationTransaction = new transactions.Generation(
@ -37,11 +44,49 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
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(){
if (!this.jobParams){
this.jobParams = [
this.jobId,
util.reverseHex(this.rpcData.previousblockhash),
this.previousHashBuffer,
this.generationTransaction.coinbase[0].toString('hex'),
this.generationTransaction.coinbase[1].toString('hex'),
this.merkleBranch,

View File

@ -67,10 +67,67 @@ var JobManager = module.exports = function JobManager(options){
jobs[this.currentJob.jobId] = 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;
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;
};

View File

@ -1,7 +1,16 @@
var net = require('net');
var bignum = require('bignum');
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){
this.options = options;
}

View File

@ -60,7 +60,7 @@ var pool = module.exports = function pool(coin){
}, function(err, results){
if (err) return;
//console.log(results);
publicKeyBuffer = coin.options.reward === 'POW' ?
util.script_to_address(results.addressInfo.address) :
@ -68,6 +68,7 @@ var pool = module.exports = function pool(coin){
_this.jobManager.newTemplate(results.rpcTemplate, publicKeyBuffer);
console.log(results.rpcTemplate);
console.log(_this.jobManager.currentJob.getJobParams());
});