public async Task <ByteString> IssueWithdrawal(IList <OutboundTransaction> transactions) { HttpClient client = new HttpClient(); BitcoinAddress address = storageKey.ScriptPubKey.GetDestinationAddress(this.Network); HttpResponseMessage response = await client.GetAsync(new Uri(url, $"addresses/{address.ToString()}/unspents")); string body = await response.Content.ReadAsStringAsync(); JArray outputs = JArray.Parse(body); TransactionBuilder builder = new TransactionBuilder(); builder.AddKeys(storageKey.GetBitcoinSecret(Network)); foreach (JObject output in outputs) { string transactionHash = (string)output["transaction_hash"]; uint outputIndex = (uint)output["output_index"]; long amount = (long)output["value"]; builder.AddCoins(new Coin(uint256.Parse(transactionHash), outputIndex, new Money(amount), storageKey.ScriptPubKey)); } foreach (OutboundTransaction outboundTransaction in transactions) { builder.Send(BitcoinAddress.Create(outboundTransaction.Target, Network).ScriptPubKey, new Money(outboundTransaction.Amount)); } builder.SendFees(defaultFees); builder.SetChange(storageKey.ScriptPubKey, ChangeType.All); NBitcoin.Transaction transaction = builder.BuildTransaction(true); return(new ByteString(transaction.ToBytes())); }
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, Money amount, ScriptVerify flags, out BitcoinConsensusError err) { var scriptPubKeyBytes = scriptPubKey.ToBytes(); var txToBytes = tx.ToBytes(); err = BitcoinConsensusError.ERR_OK; var valid = VerifyScriptConsensusWithAmount(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, amount.Satoshi, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err); return valid == 1; }
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, ScriptVerify flags) { var scriptPubKeyBytes = scriptPubKey.ToBytes(); var txToBytes = tx.ToBytes(); var err = BitcoinConsensusError.ERR_OK; var valid = VerifyScriptConsensus(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err); return(valid == 1); }
public void Serialize(BitcoinStream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } // Write the utxo // If there is a non-witness utxo, then don't serialize the witness one. if (witness_utxo != null) { // key stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_WITNESS_UTXO; stream.ReadWrite(ref key); // value var data = witness_utxo.ToBytes(); stream.ReadWriteAsVarString(ref data); } if (non_witness_utxo != null) { // key stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_NON_WITNESS_UTXO; stream.ReadWrite(ref key); // value byte[] data = non_witness_utxo.ToBytes(); stream.ReadWriteAsVarString(ref data); } // Write the sighash type if (sighash_type > 0) { stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_SIGHASH; stream.ReadWrite(ref key); var tmp = Utils.ToBytes((uint)sighash_type, true); stream.ReadWriteAsVarString(ref tmp); } // Write the redeem script if (redeem_script != null) { stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_REDEEMSCRIPT; stream.ReadWrite(ref key); var value = redeem_script.ToBytes(); stream.ReadWriteAsVarString(ref value); } // Write the witness script if (witness_script != null) { stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_WITNESSSCRIPT; stream.ReadWrite(ref key); var value = witness_script.ToBytes(); stream.ReadWriteAsVarString(ref value); } // Write any partial signatures foreach (var sig_pair in partial_sigs) { var key = new byte[] { PSBTConstants.PSBT_IN_PARTIAL_SIG }.Concat(sig_pair.Key.ToBytes()); stream.ReadWriteAsVarString(ref key); var sig = sig_pair.Value.ToBytes(); stream.ReadWriteAsVarString(ref sig); } // Write any hd keypaths foreach (var pathPair in hd_keypaths) { var key = new byte[] { PSBTConstants.PSBT_IN_BIP32_DERIVATION }.Concat(pathPair.Key.ToBytes()); stream.ReadWriteAsVarString(ref key); var masterFingerPrint = pathPair.Value.MasterFingerprint; var path = pathPair.Value.KeyPath.ToBytes(); var pathInfo = masterFingerPrint.ToBytes().Concat(path); stream.ReadWriteAsVarString(ref pathInfo); } // Write script sig if (final_script_sig != null) { stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_SCRIPTSIG; stream.ReadWrite(ref key); byte[] value = final_script_sig.ToBytes(); stream.ReadWriteAsVarString(ref value); } // write script witness if (final_script_witness != null) { stream.ReadWriteAsVarInt(ref defaultKeyLen); var key = PSBTConstants.PSBT_IN_SCRIPTWITNESS; stream.ReadWrite(ref key); var stack = final_script_witness.ToBytes(); stream.ReadWriteAsVarString(ref stack); } // Write unknown things foreach (var entry in unknown) { var k = entry.Key; var v = entry.Value; stream.ReadWriteAsVarString(ref k); stream.ReadWriteAsVarString(ref v); } var sep = PSBTConstants.PSBT_SEPARATOR; stream.ReadWrite(ref sep); }
//struct GetRejectReason() { return strRejectReason; } public bool CheckTransaction(Transaction tx) { // Basic checks that don't depend on any context if(tx.Inputs.Count == 0) return DoS(10, Utils.error("CheckTransaction() : vin empty"), RejectCode.INVALID, "bad-txns-vin-empty"); if(tx.Outputs.Count == 0) return DoS(10, Utils.error("CheckTransaction() : vout empty"), RejectCode.INVALID, "bad-txns-vout-empty"); // Size limits if(tx.ToBytes().Length > MAX_BLOCK_SIZE) return DoS(100, Utils.error("CheckTransaction() : size limits failed"), RejectCode.INVALID, "bad-txns-oversize"); // Check for negative or overflow output values long nValueOut = 0; foreach(var txout in tx.Outputs) { if(txout.Value < 0) return DoS(100, Utils.error("CheckTransaction() : txout.nValue negative"), RejectCode.INVALID, "bad-txns-vout-negative"); if(txout.Value > MAX_MONEY) return DoS(100, Utils.error("CheckTransaction() : txout.nValue too high"), RejectCode.INVALID, "bad-txns-vout-toolarge"); nValueOut += (long)txout.Value; if(!((nValueOut >= 0 && nValueOut <= (long)MAX_MONEY))) return DoS(100, Utils.error("CheckTransaction() : txout total out of range"), RejectCode.INVALID, "bad-txns-txouttotal-toolarge"); } // Check for duplicate inputs HashSet<OutPoint> vInOutPoints = new HashSet<OutPoint>(); foreach(var txin in tx.Inputs) { if(vInOutPoints.Contains(txin.PrevOut)) return DoS(100, Utils.error("CheckTransaction() : duplicate inputs"), RejectCode.INVALID, "bad-txns-inputs-duplicate"); vInOutPoints.Add(txin.PrevOut); } if(tx.IsCoinBase) { if(tx.Inputs[0].ScriptSig.Length < 2 || tx.Inputs[0].ScriptSig.Length > 100) return DoS(100, Utils.error("CheckTransaction() : coinbase script size"), RejectCode.INVALID, "bad-cb-length"); } else { foreach(var txin in tx.Inputs) if(txin.PrevOut.IsNull) return DoS(10, Utils.error("CheckTransaction() : prevout is null"), RejectCode.INVALID, "bad-txns-prevout-null"); } return true; }
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, ScriptVerify flags) { var scriptPubKeyBytes = scriptPubKey.ToBytes(); var txToBytes = tx.ToBytes(); var err = BitcoinConsensusError.ERR_OK; var valid = VerifyScriptConsensus(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err); return valid == 1; }
//https://en.bitcoin.it/wiki/OP_CHECKSIG public uint256 SignatureHash(Transaction txTo, int nIn, SigHash nHashType) { if(nIn >= txTo.Inputs.Count) { Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n"); return uint256.One; } // Check for invalid use of SIGHASH_SINGLE if(nHashType == SigHash.Single) { if(nIn >= txTo.Outputs.Count) { Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n"); return uint256.One; } } var scriptCopy = new Script(_Script); scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = new Transaction(txTo.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; var hashType = nHashType & (SigHash)31; 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 ms = new MemoryStream(); var bitcoinStream = new BitcoinStream(ms, true); txCopy.ReadWrite(bitcoinStream); bitcoinStream.ReadWrite((uint)nHashType); var hashed = ms.ToArray(); return Hashes.Hash256(hashed); }
//https://en.bitcoin.it/wiki/OP_CHECKSIG public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData) { if (sigversion == HashVersion.Witness) { if (amount == null) { throw new ArgumentException("The amount of the output being signed must be provided", "amount"); } uint256 hashPrevouts = uint256.Zero; uint256 hashSequence = uint256.Zero; uint256 hashOutputs = uint256.Zero; if ((nHashType & SigHash.AnyoneCanPay) == 0) { hashPrevouts = precomputedTransactionData == null? GetHashPrevouts(txTo) : precomputedTransactionData.HashPrevouts; } if ((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashSequence = precomputedTransactionData == null? GetHashSequence(txTo) : precomputedTransactionData.HashSequence; } if (((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { hashOutputs = precomputedTransactionData == null? GetHashOutputs(txTo) : precomputedTransactionData.HashOutputs; } else if (((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < txTo.Outputs.Count) { BitcoinStream ss = CreateHashWriter(sigversion); ss.ReadWrite(txTo.Outputs[nIn]); hashOutputs = GetHash(ss); } BitcoinStream sss = CreateHashWriter(sigversion); // Version sss.ReadWrite(txTo.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(txTo.Inputs[nIn].PrevOut); sss.ReadWrite(scriptCode); sss.ReadWrite(amount.Satoshi); sss.ReadWrite((uint)txTo.Inputs[nIn].Sequence); // Outputs (none/one/all, depending on flags) sss.ReadWrite(hashOutputs); // Locktime sss.ReadWriteStruct(txTo.LockTime); // Sighash type sss.ReadWrite((uint)nHashType); return(GetHash(sss)); } if (nIn >= txTo.Inputs.Count) { Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n"); return(uint256.One); } // Check for invalid use of SIGHASH_SINGLE if (nHashType == SigHash.Single) { if (nIn >= txTo.Outputs.Count) { Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n"); return(uint256.One); } } var scriptCopy = new Script(scriptCode._Script); scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = new Transaction(txTo.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; var hashType = nHashType & (SigHash)31; 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)nHashType); return(GetHash(stream)); }
//https://en.bitcoin.it/wiki/OP_CHECKSIG public uint256 SignatureHash(Transaction txTo, int nIn, SigHash nHashType) { if (nIn >= txTo.Inputs.Count) { Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n"); return(1); } // Check for invalid use of SIGHASH_SINGLE if (nHashType == SigHash.Single) { if (nIn >= txTo.Outputs.Count) { Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n"); return(1); } } var scriptCopy = new Script(_Script); scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = new Transaction(txTo.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 (((int)nHashType & 31) == (int)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 for (int i = 0; i < txCopy.Inputs.Count; i++) { if (i == nIn) { continue; } txCopy.Inputs[i].Sequence = 0; } } if (((int)nHashType & 31) == (int)SigHash.Single) { //The output of txCopy is resized to the size of the current input index+1. var remainingOut = txCopy.Outputs.Take(nIn + 1).ToArray(); txCopy.Outputs.Clear(); txCopy.Outputs.AddRange(remainingOut); //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 (int i = 0; i < txCopy.Outputs.Count; i++) { if (i == nIn) { continue; } txCopy.Outputs[i] = new TxOut(); } for (int i = 0; i < txCopy.Inputs.Count; i++) { //All other txCopy inputs aside from the current input are set to have an nSequence index of zero. if (i == nIn) { continue; } txCopy.Inputs[i].Sequence = 0; } } if (((int)nHashType & (int)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 MemoryStream ms = new MemoryStream(); BitcoinStream bitcoinStream = new BitcoinStream(ms, true); txCopy.ReadWrite(bitcoinStream); bitcoinStream.ReadWrite((uint)nHashType); var hashed = ms.ToArray(); return(Hashes.Hash256(hashed)); }
//https://en.bitcoin.it/wiki/OP_CHECKSIG public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount = null, HashVersion sigversion = HashVersion.Original) { if(sigversion == HashVersion.Witness) { if(amount == null) throw new ArgumentException("The amount of the output being signed must be provided", "amount"); uint256 hashPrevouts = uint256.Zero; uint256 hashSequence = uint256.Zero; uint256 hashOutputs = uint256.Zero; if((nHashType & SigHash.AnyoneCanPay) == 0) { BitcoinStream ss = CreateHashWriter(sigversion); foreach(var input in txTo.Inputs) { ss.ReadWrite(input.PrevOut); } hashPrevouts = GetHash(ss); // TODO: cache this value for all signatures in a transaction } if((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { BitcoinStream ss = CreateHashWriter(sigversion); foreach(var input in txTo.Inputs) { ss.ReadWrite((uint)input.Sequence); } hashSequence = GetHash(ss); // TODO: cache this value for all signatures in a transaction } if(((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None) { BitcoinStream ss = CreateHashWriter(sigversion); foreach(var txout in txTo.Outputs) { ss.ReadWrite(txout); } hashOutputs = GetHash(ss); // TODO: cache this value for all signatures in a transaction } else if(((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < txTo.Outputs.Count) { BitcoinStream ss = CreateHashWriter(sigversion); ss.ReadWrite(txTo.Outputs[nIn]); hashOutputs = GetHash(ss); } BitcoinStream sss = CreateHashWriter(sigversion); // Version sss.ReadWrite(txTo.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(txTo.Inputs[nIn].PrevOut); sss.ReadWrite(scriptCode); sss.ReadWrite(amount.Satoshi); sss.ReadWrite((uint)txTo.Inputs[nIn].Sequence); // Outputs (none/one/all, depending on flags) sss.ReadWrite(hashOutputs); // Locktime sss.ReadWriteStruct(txTo.LockTime); // Sighash type sss.ReadWrite((uint)nHashType); return GetHash(sss); } if(nIn >= txTo.Inputs.Count) { Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n"); return uint256.One; } // Check for invalid use of SIGHASH_SINGLE if(nHashType == SigHash.Single) { if(nIn >= txTo.Outputs.Count) { Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n"); return uint256.One; } } var scriptCopy = new Script(scriptCode._Script); scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = new Transaction(txTo.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; var hashType = nHashType & (SigHash)31; 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)nHashType); return GetHash(stream); }
//struct GetRejectReason() { return strRejectReason; } public bool CheckTransaction(Transaction tx) { // Basic checks that don't depend on any context if (tx.Inputs.Count == 0) { return(DoS(10, Utils.error("CheckTransaction() : vin empty"), RejectCode.INVALID, "bad-txns-vin-empty")); } if (tx.Outputs.Count == 0) { return(DoS(10, Utils.error("CheckTransaction() : vout empty"), RejectCode.INVALID, "bad-txns-vout-empty")); } // Size limits if (tx.ToBytes().Length > MAX_BLOCK_SIZE) { return(DoS(100, Utils.error("CheckTransaction() : size limits failed"), RejectCode.INVALID, "bad-txns-oversize")); } // Check for negative or overflow output values long nValueOut = 0; foreach (var txout in tx.Outputs) { if (txout.Value < 0) { return(DoS(100, Utils.error("CheckTransaction() : txout.nValue negative"), RejectCode.INVALID, "bad-txns-vout-negative")); } if (txout.Value > MAX_MONEY) { return(DoS(100, Utils.error("CheckTransaction() : txout.nValue too high"), RejectCode.INVALID, "bad-txns-vout-toolarge")); } nValueOut += (long)txout.Value; if (!((nValueOut >= 0 && nValueOut <= (long)MAX_MONEY))) { return(DoS(100, Utils.error("CheckTransaction() : txout total out of range"), RejectCode.INVALID, "bad-txns-txouttotal-toolarge")); } } // Check for duplicate inputs HashSet <OutPoint> vInOutPoints = new HashSet <OutPoint>(); foreach (var txin in tx.Inputs) { if (vInOutPoints.Contains(txin.PrevOut)) { return(DoS(100, Utils.error("CheckTransaction() : duplicate inputs"), RejectCode.INVALID, "bad-txns-inputs-duplicate")); } vInOutPoints.Add(txin.PrevOut); } if (tx.IsCoinBase) { if (tx.Inputs[0].ScriptSig.Length < 2 || tx.Inputs[0].ScriptSig.Length > 100) { return(DoS(100, Utils.error("CheckTransaction() : coinbase script size"), RejectCode.INVALID, "bad-cb-length")); } } else { foreach (var txin in tx.Inputs) { if (txin.PrevOut.IsNull) { return(DoS(10, Utils.error("CheckTransaction() : prevout is null"), RejectCode.INVALID, "bad-txns-prevout-null")); } } } return(true); }