public static byte[] SerializeCoinbase(IJob job, UInt32 extraNonce1) { var extraNonce1Buffer = BitConverter.GetBytes(extraNonce1.BigEndian()); byte[] result; using (var stream = new MemoryStream()) { stream.WriteBytes(job.CoinbaseInitial.HexToByteArray()); stream.WriteBytes(extraNonce1Buffer); stream.WriteBytes(job.CoinbaseFinal.HexToByteArray()); result = stream.ToArray(); } return(result); }
//Coinbase for txid hash. Should just be the coinbase with txin sig removed. There is also a bug in the //client where the msg length is written twice so this also needs to be replicated. public static byte[] SerializeCoinbaseForTxId(IJob job, UInt32 extraNonce1, UInt32 extraNonce2) { var extraNonce1Buffer = BitConverter.GetBytes(extraNonce1.BigEndian()); var extraNonce2Buffer = BitConverter.GetBytes(extraNonce2.BigEndian()); byte[] result; const int scriptSigPos = 0 + 4 // version + 1 // txin count - varint(1) + 20 // pubKey - uint160 + 8; // amount - uint64 if (job.CoinbaseInitial == null || job.CoinbaseInitial.Length <= scriptSigPos * 2) { return(null); } var initial = job.CoinbaseInitial.HexToByteArray(); byte[] initialNoSig; using (var stream = new MemoryStream()) { //write the initial excluding sig portion (1 byte - varint(0) stream.WriteBytes(initial.Take(scriptSigPos).ToArray()); stream.WriteBytes(initial.Slice(scriptSigPos + 1, initial.Length)); //replicate double msg length bug stream.WriteBytes(initial.Slice(initial.Length - 1, initial.Length)); initialNoSig = stream.ToArray(); } using (var stream = new MemoryStream()) { stream.WriteBytes(initialNoSig); stream.WriteBytes(extraNonce1Buffer); stream.WriteBytes(extraNonce2Buffer); stream.WriteBytes(job.CoinbaseFinal.HexToByteArray()); result = stream.ToArray(); } return(result); }
/// <summary> /// Block headers are sent in a headers packet in response to a getheaders message. /// </summary> /// <remarks> /// https://en.bitcoin.it/wiki/Protocol_specification#Block_Headers /// </remarks> /// <example> /// nodejs: https://github.com/zone117x/node-stratum-pool/blob/master/lib/blockTemplate.js#L85 /// </example> /// <param name="job"></param> /// <param name="merkleRoot"></param> /// <param name="nTime"></param> /// <param name="nonce"></param> /// <returns></returns> public static byte[] SerializeHeader(IJob job, byte[] merkleRoot, UInt32 nTime, UInt32 nonce) { byte[] result; using (var stream = new MemoryStream()) { stream.WriteValueU32(nonce.BigEndian()); stream.WriteValueU32(Convert.ToUInt32(job.EncodedDifficulty, 16).BigEndian()); stream.WriteValueU32(nTime.BigEndian()); stream.WriteBytes(merkleRoot); stream.WriteBytes(job.PreviousBlockHash.HexToByteArray()); stream.WriteValueU32(job.BlockTemplate.Version.BigEndian()); result = stream.ToArray(); result = result.ReverseBytes(); } return(result); }