Ejemplo n.º 1
0
        public uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, TxOut spentOutput, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
        {
            if (UsesForkId(nHashType))
            {
                uint nForkHashType = (uint)nHashType;

                nForkHashType |= (uint)ForkID << 8;
                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 < Outputs.Count)
                {
                    CoinStream ss = CreateHashWriter(sigversion);
                    ss.ReadWrite(Outputs[nIn]);
                    hashOutputs = GetHash(ss);
                }

                CoinStream sss = CreateHashWriter(sigversion);
                // Version
                sss.ReadWrite(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(nForkHashType);

                return(GetHash(sss));
            }

            if (nIn >= Inputs.Count)
            {
                return(uint256.One);
            }

            SigHash hashType = nHashType & (SigHash)31;

            // Check for invalid use of SIGHASH_SINGLE
            if (hashType == SigHash.Single)
            {
                if (nIn >= Outputs.Count)
                {
                    return(uint256.One);
                }
            }

            Script scriptCopy = scriptCode.Clone();

            scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

            if (!CustomTransaction.GetCustomTransaction(CurrencyID, out Transaction txCopy))
            {
                txCopy = new Transaction();
            }

            txCopy.FromBytes(this.ToBytes());
            //Set all TxIn script to empty string
            foreach (TxIn 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 (TxIn 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 (int 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 (TxIn 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.
                TxIn 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
            CoinStream stream = CreateHashWriter(sigversion);

            txCopy.ReadWrite(stream);
            //stream.ReadWrite(nForkHashType);
            return(GetHash(stream));
        }
Ejemplo n.º 2
0
        public virtual string SignTransaction(string aTxData, ICurrencyTransaction aValidationInfo)
        {
            if (!CustomTransaction.GetCustomTransaction(Id, out Transaction tx, aTxData, Network))
            {
                tx = new Transaction(aTxData, Network);
            }
            // check how much is being spent and insure all is spent.
            BigInteger lTotalSent = 0;

            foreach (ITransactionUnit linput in aValidationInfo.Inputs)
            {
                lTotalSent += linput.Amount;
            }

            BigInteger lTotalSpending = aValidationInfo.TxFee;

            foreach (ITransactionUnit lOutput in aValidationInfo.Outputs)
            {
                lTotalSpending += lOutput.Amount;
            }

            if (lTotalSent != lTotalSpending)
            {
                throw new Exception("The total of the inputs does not equal the total outputs.");
            }
            // Check output amounts in the transaction to sign.
            int lValidCount = 0;

            foreach (TxOut lOutput in tx.Outputs)
            {
                string lAddress = lOutput.GetAddress(Network);
                foreach (ITransactionUnit lValOut in aValidationInfo.Outputs)
                {
                    if (lAddress == lValOut.Address)
                    {
                        if (lOutput.Value.Satoshi == lValOut.Amount)
                        {
                            lValidCount++;
                        }
                    }
                }
            }
            if (lValidCount != aValidationInfo.Outputs.Length)
            {
                throw new Exception("Transaction to sign is not correct.");
            }

            List <CCKey> lKeys  = new List <CCKey>();
            List <ICoin> lCoins = new List <ICoin>();

            for (int i = 0; i < tx.Inputs.Count; i++)
            {
                if (!FAddressLookup.TryGetValue(aValidationInfo.Inputs[i].Address, out long lIndex))
                {
                    throw new Exception(string.Format("Address {0} does not exist.", aValidationInfo.Inputs[i].Address));
                }

                lKeys.Add(GetCCKey(lIndex));
                ITransactionUnit lPrevOut = aValidationInfo.Inputs
                                            .Where(lInput => lInput.TxID == tx.Inputs[i].PrevOut.Hash.ToString() && lInput.Index == tx.Inputs[i].PrevOut.N)
                                            .FirstOrDefault();
                if (lPrevOut == null)
                {
                    throw new Exception("Failed to found previous tx out information");
                }
                lCoins.Add(new Coin(tx.Inputs[i].PrevOut, new TxOut()
                {
                    ScriptPubKey = tx.Inputs[i].ScriptSig,
                    Value        = new Money((long)lPrevOut.Amount)
                }));
                tx.Inputs[i].ScriptSig = Script.Empty;
            }

            var lHexTest = tx.ToHex();

            tx.Sign(lKeys.ToArray(), lCoins.ToArray());
            return(tx.ToHex());
        }