diff --git a/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs b/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs index 86bf51285..ce28737aa 100644 --- a/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/MiningCore/Blockchain/Bitcoin/BitcoinJob.cs @@ -116,94 +116,120 @@ protected virtual void BuildMerkleBranches() .ToArray(); } - protected virtual void BuildCoinbase() - { - // generate script parts - var sigScriptInitial = GenerateScriptSigInitial(); - var sigScriptInitialBytes = sigScriptInitial.ToBytes(); - - var sigScriptLength = (uint) ( - sigScriptInitial.Length + - extraNoncePlaceHolderLength + - scriptSigFinalBytes.Length); - - // output transaction - txOut = CreateOutputTransaction(); - - // build coinbase initial - using (var stream = new MemoryStream()) - { - var bs = new BitcoinStream(stream, true); - - // version - bs.ReadWrite(ref txVersion); - - // timestamp for POS coins - if (isPoS) - { - var timestamp = BlockTemplate.CurTime; - bs.ReadWrite(ref timestamp); - } - - // serialize (simulated) input transaction - bs.ReadWriteAsVarInt(ref txInputCount); - bs.ReadWrite(ref sha256Empty); - bs.ReadWrite(ref txInPrevOutIndex); - - // signature script initial part - bs.ReadWriteAsVarInt(ref sigScriptLength); - bs.ReadWrite(ref sigScriptInitialBytes); - - // done - coinbaseInitial = stream.ToArray(); - coinbaseInitialHex = coinbaseInitial.ToHexString(); - } - - // build coinbase final - using (var stream = new MemoryStream()) - { - var bs = new BitcoinStream(stream, true); - - // signature script final part - bs.ReadWrite(ref scriptSigFinalBytes); - - // tx in sequence - bs.ReadWrite(ref txInSequence); - - // serialize output transaction - var txOutBytes = SerializeOutputTransaction(txOut); - bs.ReadWrite(ref txOutBytes); - - // misc - bs.ReadWrite(ref txLockTime); - - // done - coinbaseFinal = stream.ToArray(); - coinbaseFinalHex = coinbaseFinal.ToHexString(); - } - } - - protected virtual byte[] SerializeOutputTransaction(Transaction tx) - { - using (var stream = new MemoryStream()) - { - var bs = new BitcoinStream(stream, true); - - // serialize outputs - var vout = tx.Outputs; - bs.ReadWrite(ref vout); - - // serialize witness (segwit) - if (!string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment)) - { - var witScript = new WitScript(BlockTemplate.DefaultWitnessCommitment); - var raw = witScript.ToBytes(); - bs.ReadWrite(ref raw); - } - - return stream.ToArray(); - } - } + protected virtual void BuildCoinbase() + { + // generate script parts + var sigScriptInitial = GenerateScriptSigInitial(); + var sigScriptInitialBytes = sigScriptInitial.ToBytes(); + + var sigScriptLength = (uint) ( + sigScriptInitial.Length + + extraNoncePlaceHolderLength + + scriptSigFinalBytes.Length); + + // output transaction + txOut = CreateOutputTransaction(); + + // build coinbase initial + using (var stream = new MemoryStream()) + { + var bs = new BitcoinStream(stream, true); + + // version + bs.ReadWrite(ref txVersion); + + // timestamp for POS coins + if (isPoS) + { + var timestamp = BlockTemplate.CurTime; + bs.ReadWrite(ref timestamp); + } + + // serialize (simulated) input transaction + bs.ReadWriteAsVarInt(ref txInputCount); + bs.ReadWrite(ref sha256Empty); + bs.ReadWrite(ref txInPrevOutIndex); + + // signature script initial part + bs.ReadWriteAsVarInt(ref sigScriptLength); + bs.ReadWrite(ref sigScriptInitialBytes); + + // done + coinbaseInitial = stream.ToArray(); + coinbaseInitialHex = coinbaseInitial.ToHexString(); + } + + // build coinbase final + using (var stream = new MemoryStream()) + { + var bs = new BitcoinStream(stream, true); + + // signature script final part + bs.ReadWrite(ref scriptSigFinalBytes); + + // tx in sequence + bs.ReadWrite(ref txInSequence); + + // serialize output transaction + var txOutBytes = SerializeOutputTransaction(txOut); + bs.ReadWrite(ref txOutBytes); + + // misc + bs.ReadWrite(ref txLockTime); + + // done + coinbaseFinal = stream.ToArray(); + coinbaseFinalHex = coinbaseFinal.ToHexString(); + } + } + + protected virtual byte[] SerializeOutputTransaction(Transaction tx) + { + var withDefaultWitnessCommitment = !string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment); + + var outputCount = (uint)tx.Outputs.Count; + if (withDefaultWitnessCommitment) + outputCount++; + + using (var stream = new MemoryStream()) + { + var bs = new BitcoinStream(stream, true); + + // write output count + bs.ReadWriteAsVarInt(ref outputCount); + + long amount; + byte[] raw; + uint rawLength; + + // serialize witness (segwit) + if (withDefaultWitnessCommitment) + { + amount = 0; + raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); + rawLength = (uint)raw.Length; + + bs.ReadWrite(ref amount); + bs.ReadWriteAsVarInt(ref rawLength); + bs.ReadWrite(ref raw); + } + + // serialize outputs + foreach (var output in tx.Outputs) + { + amount = output.Value.Satoshi; + var outScript = output.ScriptPubKey; + raw = outScript.ToBytes(true); + rawLength = (uint)raw.Length; + + bs.ReadWrite(ref amount); + bs.ReadWriteAsVarInt(ref rawLength); + bs.ReadWrite(ref raw); + } + + return stream.ToArray(); + } + } protected virtual Script GenerateScriptSigInitial() {