static uint256 GetHashToSign(Transaction tx, int index, Script scriptCode, long amount) { const SigHash sigHash = SigHash.All; uint256 hashPrevouts = GetHashPrevouts(tx); uint256 hashSequence = GetHashSequence(tx); uint256 hashOutputs = GetHashOutputs(tx); BitcoinStream stream = CreateHashWriter(HashVersion.Witness); stream.ReadWrite(tx.Version); // Input prevouts/nSequence (none/all, depending on flags) stream.ReadWrite(hashPrevouts); stream.ReadWrite(hashSequence); // The input being signed (replacing the scriptSig with scriptCode + amount) // The prevout may already be contained in hashPrevout, and the nSequence // may already be contain in hashSequence. stream.ReadWrite(tx.Inputs[index].PrevOut); stream.ReadWrite(scriptCode); stream.ReadWrite(amount); // ReSharper disable once RedundantCast stream.ReadWrite((uint)tx.Inputs[index].Sequence); // Outputs (none/one/all, depending on flags) stream.ReadWrite(hashOutputs); // Locktime stream.ReadWriteStruct(tx.LockTime); // Sighash type stream.ReadWrite((uint)sigHash); return(GetHash(stream)); }
private void SerializeTxn(BitcoinStream stream) { var version = this.Version; stream.ReadWrite(ref version); // POS Timestamp var time = this.Time; stream.ReadWrite(ref time); TxInList vin = this.Inputs; stream.ReadWrite(ref vin); vin.Transaction = this; TxOutList vout = this.Outputs; stream.ReadWrite(ref vout); vout.Transaction = this; LockTime lockTime = this.LockTime; stream.ReadWriteStruct(ref lockTime); }
private void DeserializeTxn(BitcoinStream stream) { UInt32 nVersionTemp = 0; stream.ReadWrite(ref nVersionTemp); // POS time stamp UInt32 nTimeTemp = 0; stream.ReadWrite(ref nTimeTemp); TxInList vinTemp = null; TxOutList voutTemp = null; // Try to read the vin. stream.ReadWrite(ref vinTemp); vinTemp.Transaction = this; // Assume a normal vout follows. stream.ReadWrite(ref voutTemp); voutTemp.Transaction = this; LockTime lockTimeTemp = LockTime.Zero; stream.ReadWriteStruct(ref lockTimeTemp); this.Version = nVersionTemp; this.Time = nTimeTemp; // POS Timestamp vinTemp.ForEach(i => this.Inputs.Add(i)); voutTemp.ForEach(i => this.Outputs.Add(i)); this.LockTime = lockTimeTemp; }
private void SerializeTxn(BitcoinStream stream, bool witSupported) { byte flags = 0; var version = (witSupported && (this.Inputs.Count == 0 && this.Outputs.Count > 0)) ? this.Version | NoDummyInput : this.Version; stream.ReadWrite(ref version); // POS Timestamp var time = this.Time; stream.ReadWrite(ref time); if (witSupported) { // Check whether witnesses need to be serialized. if (HasWitness) { flags |= 1; } } if (flags != 0) { // Use extended format in case witnesses are to be serialized. TxInList vinDummy = new TxInList(); stream.ReadWrite <TxInList, TxIn>(ref vinDummy); stream.ReadWrite(ref flags); } TxInList vin = this.Inputs; stream.ReadWrite <TxInList, TxIn>(ref vin); vin.Transaction = this; TxOutList vout = this.Outputs; stream.ReadWrite <TxOutList, TxOut>(ref vout); vout.Transaction = this; if ((flags & 1) != 0) { StratisWitness wit = new StratisWitness(this.Inputs); wit.ReadWrite(stream); } LockTime lockTime = this.LockTime; stream.ReadWriteStruct(ref lockTime); }
public override void ReadWrite(BitcoinStream stream) { stream.ReadWrite(ref nVersion); stream.ReadWriteStruct(ref nLockTime); stream.ReadWrite <TxInList, TxIn>(ref vin); vin.Transaction = this; stream.ReadWrite <TxOutList, TxOut>(ref vout); vout.Transaction = this; if (stream.Type != SerializationType.Hash) { Witness wit = new Witness(Inputs); try { wit.ReadWrite(stream); } catch (FormatException e) { Console.Out.WriteLine(e.Message); } } }
public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, TxOut spentOutput, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData) { uint nForkHashType = (uint)nHashType; if (UsesForkId(nHashType)) { nForkHashType |= ForkId << 8; } if ((SupportSegwit && sigversion == HashVersion.Witness) || UsesForkId(nHashType)) { if (spentOutput?.Value == null || spentOutput.Value == TxOut.NullMoney) { throw new ArgumentException("The output being signed with the amount must be provided", nameof(spentOutput)); } uint256 hashPrevouts = uint256.Zero; uint256 hashSequence = uint256.Zero; uint256 hashOutputs = uint256.Zero; if ((nHashType & SigHash.AnyoneCanPay) == 0) { hashPrevouts = precomputedTransactionData == null? GetHashPrevouts() : precomputedTransactionData.HashPrevouts; } if ((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashSequence = precomputedTransactionData == null? GetHashSequence() : precomputedTransactionData.HashSequence; } if (((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashOutputs = precomputedTransactionData == null? GetHashOutputs() : precomputedTransactionData.HashOutputs; } else if (((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < this.Outputs.Count) { BitcoinStream ss = CreateHashWriter(sigversion); ss.ReadWrite(this.Outputs[nIn]); hashOutputs = GetHash(ss); } BitcoinStream sss = CreateHashWriter(sigversion); // Version sss.ReadWrite(this.Version); // Input prevouts/nSequence (none/all, depending on flags) sss.ReadWrite(hashPrevouts); sss.ReadWrite(hashSequence); // The input being signed (replacing the scriptSig with scriptCode + amount) // The prevout may already be contained in hashPrevout, and the nSequence // may already be contain in hashSequence. sss.ReadWrite(Inputs[nIn].PrevOut); sss.ReadWrite(scriptCode); sss.ReadWrite(spentOutput.Value.Satoshi); sss.ReadWrite((uint)Inputs[nIn].Sequence); // Outputs (none/one/all, depending on flags) sss.ReadWrite(hashOutputs); // Locktime sss.ReadWriteStruct(LockTime); // Sighash type sss.ReadWrite((uint)nForkHashType); return(GetHash(sss)); } if (nIn >= Inputs.Count) { return(uint256.One); } var hashType = nHashType & (SigHash)31; // Check for invalid use of SIGHASH_SINGLE if (hashType == SigHash.Single) { if (nIn >= Outputs.Count) { return(uint256.One); } } var scriptCopy = scriptCode.Clone(); scriptCode = scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = GetConsensusFactory().CreateTransaction(); txCopy.FromBytes(this.ToBytes()); //Set all TxIn script to empty string foreach (var txin in txCopy.Inputs) { txin.ScriptSig = new Script(); } //Copy subscript into the txin script you are checking txCopy.Inputs[nIn].ScriptSig = scriptCopy; if (hashType == SigHash.None) { //The output of txCopy is set to a vector of zero size. txCopy.Outputs.Clear(); //All other inputs aside from the current input in txCopy have their nSequence index set to zero foreach (var input in txCopy.Inputs.Where((x, i) => i != nIn)) { input.Sequence = 0; } } else if (hashType == SigHash.Single) { //The output of txCopy is resized to the size of the current input index+1. txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1)); //All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1. for (var i = 0; i < txCopy.Outputs.Count; i++) { if (i == nIn) { continue; } txCopy.Outputs[i] = new TxOut(); } //All other txCopy inputs aside from the current input are set to have an nSequence index of zero. foreach (var input in txCopy.Inputs.Where((x, i) => i != nIn)) { input.Sequence = 0; } } if ((nHashType & SigHash.AnyoneCanPay) != 0) { //The txCopy input vector is resized to a length of one. var script = txCopy.Inputs[nIn]; txCopy.Inputs.Clear(); txCopy.Inputs.Add(script); //The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector. txCopy.Inputs[0].ScriptSig = scriptCopy; } //Serialize TxCopy, append 4 byte hashtypecode var stream = CreateHashWriter(sigversion); txCopy.ReadWrite(stream); stream.ReadWrite((uint)nForkHashType); return(GetHash(stream)); }
private void DeserializeTxn(BitcoinStream stream, bool witSupported) { byte flags = 0; UInt32 nVersionTemp = 0; stream.ReadWrite(ref nVersionTemp); // POS time stamp uint nTimeTemp = 0; stream.ReadWrite(ref nTimeTemp); TxInList vinTemp = new TxInList(); TxOutList voutTemp = new TxOutList(); // Try to read the vin. In case the dummy is there, this will be read as an empty vector. stream.ReadWrite <TxInList, TxIn>(ref vinTemp); var hasNoDummy = (nVersionTemp & NoDummyInput) != 0 && vinTemp.Count == 0; if (witSupported && hasNoDummy) { nVersionTemp = nVersionTemp & ~NoDummyInput; } if (vinTemp.Count == 0 && witSupported && !hasNoDummy) { // We read a dummy or an empty vin. stream.ReadWrite(ref flags); if (flags != 0) { // Assume we read a dummy and a flag. stream.ReadWrite <TxInList, TxIn>(ref vinTemp); vinTemp.Transaction = this; stream.ReadWrite <TxOutList, TxOut>(ref voutTemp); voutTemp.Transaction = this; } else { // Assume read a transaction without output. voutTemp = new TxOutList(); voutTemp.Transaction = this; } } else { // We read a non-empty vin. Assume a normal vout follows. stream.ReadWrite <TxOutList, TxOut>(ref voutTemp); voutTemp.Transaction = this; } if (((flags & 1) != 0) && witSupported) { // The witness flag is present, and we support witnesses. flags ^= 1; StratisWitness wit = new StratisWitness(vinTemp); wit.ReadWrite(stream); } if (flags != 0) { // Unknown flag in the serialization throw new FormatException("Unknown transaction optional data"); } LockTime lockTimeTemp = LockTime.Zero; stream.ReadWriteStruct(ref lockTimeTemp); this.Version = nVersionTemp; this.Time = nTimeTemp; // POS Timestamp vinTemp.ForEach(i => this.AddInput(i)); voutTemp.ForEach(i => this.AddOutput(i)); this.LockTime = lockTimeTemp; }
public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, TxOut spentOutput, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData) { if (sigversion == HashVersion.WitnessV0) { if (spentOutput?.Value == null || spentOutput.Value == TxOut.NullMoney) { throw new ArgumentException("The output being signed with the amount must be provided", nameof(spentOutput)); } uint256 hashPrevouts = uint256.Zero; uint256 hashSequence = uint256.Zero; uint256 hashOutputs = uint256.Zero; if ((nHashType & SigHash.AnyoneCanPay) == 0) { hashPrevouts = precomputedTransactionData == null? GetHashPrevouts() : precomputedTransactionData.HashPrevouts; } if ((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashSequence = precomputedTransactionData == null? GetHashSequence() : precomputedTransactionData.HashSequence; } if (((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashOutputs = precomputedTransactionData == null? GetHashOutputs() : precomputedTransactionData.HashOutputs; } else if (((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < this.Outputs.Count) { BitcoinStream ss = CreateHashWriter(sigversion); ss.ReadWrite(this.Outputs[nIn]); hashOutputs = GetHash(ss); } BitcoinStream sss = CreateHashWriter(sigversion); // Version sss.ReadWrite(this.Version); // PoS Time sss.ReadWrite(this.Time); // Input prevouts/nSequence (none/all, depending on flags) sss.ReadWrite(hashPrevouts); sss.ReadWrite(hashSequence); // The input being signed (replacing the scriptSig with scriptCode + amount) // The prevout may already be contained in hashPrevout, and the nSequence // may already be contain in hashSequence. sss.ReadWrite(Inputs[nIn].PrevOut); sss.ReadWrite(scriptCode); sss.ReadWrite(spentOutput.Value.Satoshi); sss.ReadWrite(Inputs[nIn].Sequence); // Outputs (none/one/all, depending on flags) sss.ReadWrite(hashOutputs); // Locktime sss.ReadWriteStruct(LockTime); // Sighash type sss.ReadWrite((uint)nHashType); return(GetHash(sss)); } bool fAnyoneCanPay = (nHashType & SigHash.AnyoneCanPay) != 0; bool fHashSingle = ((byte)nHashType & 0x1f) == (byte)SigHash.Single; bool fHashNone = ((byte)nHashType & 0x1f) == (byte)SigHash.None; if (nIn >= Inputs.Count) { return(uint256.One); } if (fHashSingle) { if (nIn >= Outputs.Count) { return(uint256.One); } } var stream = CreateHashWriter(sigversion); stream.ReadWrite(Version); stream.ReadWrite(Time); uint nInputs = (uint)(fAnyoneCanPay ? 1 : Inputs.Count); stream.ReadWriteAsVarInt(ref nInputs); for (int nInput = 0; nInput < nInputs; nInput++) { if (fAnyoneCanPay) { nInput = nIn; } stream.ReadWrite(Inputs[nInput].PrevOut); if (nInput != nIn) { stream.ReadWrite(Script.Empty); } else { WriteScriptCode(stream, scriptCode); } if (nInput != nIn && (fHashSingle || fHashNone)) { stream.ReadWrite((uint)0); } else { stream.ReadWrite(Inputs[nInput].Sequence); } } uint nOutputs = (uint)(fHashNone ? 0 : (fHashSingle ? nIn + 1 : Outputs.Count)); stream.ReadWriteAsVarInt(ref nOutputs); for (int nOutput = 0; nOutput < nOutputs; nOutput++) { if (fHashSingle && nOutput != nIn) { this.Outputs.CreateNewTxOut().ReadWrite(stream); } else { Outputs[nOutput].ReadWrite(stream); } } stream.ReadWriteStruct(LockTime); stream.ReadWrite((uint)nHashType); return(GetHash(stream)); }
public override void ReadWrite(BitcoinStream stream) { bool witSupported = (((uint)stream.TransactionOptions & (uint)TransactionOptions.Witness) != 0) && stream.ProtocolVersion >= ProtocolVersion.WITNESS_VERSION; byte flags = 0; if (!stream.Serializing) { stream.ReadWrite(ref this.nVersion); // POS time stamp stream.ReadWrite(ref this.nTime); /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */ stream.ReadWrite <TxInList, TxIn>(ref this.vin); bool hasNoDummy = (this.nVersion & NoDummyInput) != 0 && this.vin.Count == 0; if (witSupported && hasNoDummy) { this.nVersion = this.nVersion & ~NoDummyInput; } if (this.vin.Count == 0 && witSupported && !hasNoDummy) { /* We read a dummy or an empty vin. */ stream.ReadWrite(ref flags); if (flags != 0) { /* Assume we read a dummy and a flag. */ stream.ReadWrite <TxInList, TxIn>(ref this.vin); this.vin.Transaction = this; stream.ReadWrite <TxOutList, TxOut>(ref this.vout); this.vout.Transaction = this; } else { /* Assume read a transaction without output. */ this.vout = new TxOutList(); this.vout.Transaction = this; } } else { /* We read a non-empty vin. Assume a normal vout follows. */ stream.ReadWrite <TxOutList, TxOut>(ref this.vout); this.vout.Transaction = this; } if (((flags & 1) != 0) && witSupported) { /* The witness flag is present, and we support witnesses. */ flags ^= 1; var wit = new Witness(this.Inputs); wit.ReadWrite(stream); } if (flags != 0) { /* Unknown flag in the serialization */ throw new FormatException("Unknown transaction optional data"); } } else { uint version = (witSupported && (this.vin.Count == 0 && this.vout.Count > 0)) ? this.nVersion | NoDummyInput : this.nVersion; stream.ReadWrite(ref version); // the POS time stamp stream.ReadWrite(ref this.nTime); if (witSupported) { /* Check whether witnesses need to be serialized. */ if (this.HasWitness) { flags |= 1; } } if (flags != 0) { /* Use extended format in case witnesses are to be serialized. */ var vinDummy = new TxInList(); stream.ReadWrite <TxInList, TxIn>(ref vinDummy); stream.ReadWrite(ref flags); } stream.ReadWrite <TxInList, TxIn>(ref this.vin); this.vin.Transaction = this; stream.ReadWrite <TxOutList, TxOut>(ref this.vout); this.vout.Transaction = this; if ((flags & 1) != 0) { var wit = new Witness(this.Inputs); wit.ReadWrite(stream); } } stream.ReadWriteStruct(ref this.nLockTime); }