var util = require('./util.js'); /* function Transaction(params){ var version = params.version || 1, inputs = params.inputs || [], outputs = params.outputs || [], lockTime = params.lockTime || 0; this.toBuffer = function(){ return Buffer.concat([ binpack.packUInt32(version, 'little'), util.varIntBuffer(inputs.length), Buffer.concat(inputs.map(function(i){ return i.toBuffer() })), util.varIntBuffer(outputs.length), Buffer.concat(outputs.map(function(o){ return o.toBuffer() })), binpack.packUInt32(lockTime, 'little') ]); }; this.inputs = inputs; this.outputs = outputs; } function TransactionInput(params){ var prevOutHash = params.prevOutHash || 0, prevOutIndex = params.prevOutIndex, sigScript = params.sigScript, sequence = params.sequence || 0; this.toBuffer = function(){ sigScriptBuffer = sigScript.toBuffer(); console.log('scriptSig length ' + sigScriptBuffer.length); return Buffer.concat([ util.uint256BufferFromHash(prevOutHash), binpack.packUInt32(prevOutIndex, 'little'), util.varIntBuffer(sigScriptBuffer.length), sigScriptBuffer, binpack.packUInt32(sequence) ]); }; } function TransactionOutput(params){ var value = params.value, pkScriptBuffer = params.pkScriptBuffer; this.toBuffer = function(){ return Buffer.concat([ binpack.packInt64(value, 'little'), util.varIntBuffer(pkScriptBuffer.length), pkScriptBuffer ]); }; } function ScriptSig(params){ var height = params.height, flags = params.flags, extraNoncePlaceholder = params.extraNoncePlaceholder; this.toBuffer = function(){ return Buffer.concat([ util.serializeNumber(height), new Buffer(flags, 'hex'), util.serializeNumber(Date.now() / 1000 | 0), new Buffer([extraNoncePlaceholder.length]), extraNoncePlaceholder, util.serializeString('/nodeStratum/') ]); } }; var Generation = exports.Generation = function Generation(rpcData, publicKey, extraNoncePlaceholder){ var tx = new Transaction({ inputs: [new TransactionInput({ prevOutIndex : Math.pow(2, 32) - 1, sigScript : new ScriptSig({ height : rpcData.height, flags : rpcData.coinbaseaux.flags, extraNoncePlaceholder : extraNoncePlaceholder }) })], outputs: [new TransactionOutput({ value : rpcData.coinbasevalue, pkScriptBuffer : publicKey })] }); var txBuffer = tx.toBuffer(); var epIndex = buffertools.indexOf(txBuffer, extraNoncePlaceholder); var p1 = txBuffer.slice(0, epIndex); var p2 = txBuffer.slice(epIndex + extraNoncePlaceholder.length); this.transaction = tx; this.coinbase = [p1, p2]; }; */ /* ^^^^ The above code was a bit slow. The below code is uglier but optimized. */ /* This function creates the generation transaction that accepts the reward for successfully mining a new block. For some (probably outdated and incorrect) documentation about whats kinda going on here, see: https://en.bitcoin.it/wiki/Protocol_specification#tx */ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, reward, txMessages){ var txInputsCount = 1; var txOutputsCount = 1; var txVersion = txMessages === true ? 2 : 1; var txLockTime = 0; var txInPrevOutHash = 0; var txInPrevOutIndex = Math.pow(2, 32) - 1; var txInSequence = 0; //Only required for POS coins var txTimestamp = reward === 'POS' ? util.packUInt32LE(rpcData.curtime) : new Buffer([]); //For coins that support/require transaction comments var txComment = txMessages === true ? util.serializeString('https://github.com/zone117x/node-stratum') : new Buffer([]); var scriptSigPart1 = Buffer.concat([ util.serializeNumber(rpcData.height), new Buffer(rpcData.coinbaseaux.flags, 'hex'), util.serializeNumber(Date.now() / 1000 | 0), new Buffer([extraNoncePlaceholder.length]) ]); var scriptSigPart2 = util.serializeString('/nodeStratum/'); var p1 = Buffer.concat([ util.packUInt32LE(txVersion), txTimestamp, util.varIntBuffer(txInputsCount), //transaction input util.uint256BufferFromHash(txInPrevOutHash), util.packUInt32LE(txInPrevOutIndex), util.varIntBuffer(scriptSigPart1.length + extraNoncePlaceholder.length + scriptSigPart2.length), scriptSigPart1 ]); /* The generation transaction must be split at the extranonce (which located in the transaction input scriptSig). Miners send us unique extranonces that we use to join the two parts in attempt to create a valid share and/or block. */ var p2 = Buffer.concat([ scriptSigPart2, util.packUInt32LE(txInSequence), //end transaction input util.varIntBuffer(txOutputsCount), //transaction output util.packInt64LE(rpcData.coinbasevalue), util.varIntBuffer(publicKey.length), publicKey, //end transaction ouput util.packUInt32LE(txLockTime), txComment ]); return [p1, p2]; };