/// <summary>
        /// Generation of SignatureHash. This method is responsible for removal of transaction metadata. It's necessary signature can't sign itself. 
        /// </summary>
        /// <param name="script">Spending instructions</param>
        /// <param name="txTo">Instance of transaction</param>
        /// <param name="nIn">Input number</param>
        /// <param name="nHashType">Hash type flag</param>
        /// <returns></returns>
        public static uint256 SignatureHash(CScript script, CTransaction txTo, int nIn, int nHashType)
        {
            Contract.Requires<ArgumentOutOfRangeException>(nIn < txTo.vin.Length, "nIn out of range.");

            // Init a copy of transaction
            var txTmp = new CTransaction(txTo);

            // In case concatenating two scripts ends up with two codeseparators,
            // or an extra one at the end, this prevents all those possible incompatibilities.
            script.RemoveInstruction(instruction.OP_CODESEPARATOR);

            // Blank out other inputs' signatures
            for (int i = 0; i < txTmp.vin.Length; i++)
            {
                txTmp.vin[i].scriptSig = new CScript();
            }
            txTmp.vin[nIn].scriptSig = script;

            // Blank out some of the outputs
            if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
            {
                // Wildcard payee
                txTmp.vout = new CTxOut[0];

                // Let the others update at will
                for (int i = 0; i < txTmp.vin.Length; i++)
                {
                    if (i != nIn)
                    {
                        txTmp.vin[i].nSequence = 0;
                    }
                }
            }
            else if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_SINGLE)
            {
                // Only lock-in the txout payee at same index as txin
                int nOut = nIn;
                if (nOut >= txTmp.vout.Length)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("ERROR: SignatureHash() : nOut={0} out of range\n", nOut);
                    throw new ArgumentOutOfRangeException("nOut", sb.ToString());
                }
                Array.Resize(ref txTmp.vout, nOut + 1);

                for (int i = 0; i < nOut; i++)
                {
                    txTmp.vout[i] = new CTxOut();
                }

                // Let the others update at will
                for (int i = 0; i < txTmp.vin.Length; i++)
                {
                    if (i != nIn)
                    {
                        txTmp.vin[i].nSequence = 0;
                    }
                }
            }

            // Blank out other inputs completely, not recommended for open transactions
            if ((nHashType & (int)sigflag.SIGHASH_ANYONECANPAY) != 0)
            {
                txTmp.vin[0] = txTmp.vin[nIn];
                Array.Resize(ref txTmp.vin, 1);
            }

            // Concatenate and hash
            var txBytes = (byte[])txTmp;
            var nHashTypeBytes = BitConverter.GetBytes(nHashType);

            return CryptoUtils.ComputeHash256(ref txBytes, ref nHashTypeBytes);
        }