From 7a21abacc48664ec46b7bc3efc50f8427d8a1e38 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Tue, 7 Jan 2014 03:23:56 -0500 Subject: [PATCH] updated --- README.md | 2 +- blockTemplate.js | 47 +++++++++++++++++++++++++++++++++++++- jobManager.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++- main.js | 9 ++++++++ pool.js | 3 ++- 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 74d812e..ae10648 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/blockTemplate.js b/blockTemplate.js index b476c73..b0e226b 100644 --- a/blockTemplate.js +++ b/blockTemplate.js @@ -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, diff --git a/jobManager.js b/jobManager.js index 2095a6a..009391d 100644 --- a/jobManager.js +++ b/jobManager.js @@ -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; }; diff --git a/main.js b/main.js index d8619f8..7c12cbe 100644 --- a/main.js +++ b/main.js @@ -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; } diff --git a/pool.js b/pool.js index 02f600e..d532904 100644 --- a/pool.js +++ b/pool.js @@ -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()); });