Turn ByteQueue into MemoryStream wrapper, use MemoryStream for serialization of COutP...
[NovacoinLibrary.git] / Novacoin / CTxIn.cs
index 59ddc40..067ad46 100644 (file)
@@ -1,23 +1,55 @@
-\feffusing System;
+\feff/**
+ *  Novacoin classes library
+ *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
+
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using System;
 using System.Text;
 using System.Collections.Generic;
+using System.IO;
 
 namespace Novacoin
 {
-       /// <summary>
-       /// Transaction input.
-       /// </summary>
-       public class CTxIn
-       {
-               /// <summary>
-               /// Hash of parent transaction.
-               /// </summary>
-               public Hash256 txID = new Hash256();
+    [Serializable]
+    public class TxInConstructorException : Exception
+    {
+        public TxInConstructorException()
+        {
+        }
 
-               /// <summary>
-               /// Parent input number.
-               /// </summary>
-        public uint n = 0;
+        public TxInConstructorException(string message)
+                : base(message)
+        {
+        }
+
+        public TxInConstructorException(string message, Exception inner)
+                : base(message, inner)
+        {
+        }
+    }
+
+    /// <summary>
+    /// Transaction input.
+    /// </summary>
+    public class CTxIn
+       {
+        /// <summary>
+        /// Previous input data
+        /// </summary>
+        public COutPoint prevout;
 
                /// <summary>
                /// First half of script, signatures for the scriptPubKey
@@ -27,7 +59,7 @@ namespace Novacoin
                /// <summary>
                /// Transaction variant number, irrelevant if nLockTime isn't specified. Its value is 0xffffffff by default.
                /// </summary>
-        public uint nSequence = 0xffffffff;
+        public uint nSequence = uint.MaxValue;
 
         /// <summary>
         /// Initialize new CTxIn instance as copy of another one.
@@ -35,8 +67,7 @@ namespace Novacoin
         /// <param name="i">CTxIn instance.</param>
         public CTxIn(CTxIn i)
         {
-            txID = i.txID;
-            n = i.n;
+            prevout = new COutPoint(i.prevout);
             scriptSig = i.scriptSig;
             nSequence = i.nSequence;
         }
@@ -46,6 +77,8 @@ namespace Novacoin
         /// </summary>
         public CTxIn()
         {
+            prevout = new COutPoint();
+            scriptSig = new CScript();
         }
 
         /// <summary>
@@ -53,73 +86,95 @@ namespace Novacoin
         /// </summary>
         /// <param name="wBytes">Reference to byte sequence</param>
         /// <returns>Inputs array</returns>
-        public static CTxIn[] ReadTxInList(ref WrappedList<byte> wBytes)
+        public static CTxIn[] ReadTxInList(ref ByteQueue wBytes)
         {
-            CTxIn[] vin;
-
-            // Get amount
-            int nInputs = (int)VarInt.ReadVarInt(ref wBytes);
-            vin = new CTxIn[nInputs];
-
-            for (int nIndex = 0; nIndex < nInputs; nIndex++)
+            try
             {
-                // Fill inputs array
-                vin[nIndex] = new CTxIn();
-
-                vin[nIndex].txID = new Hash256(wBytes.GetItems(32));
-                vin[nIndex].n = BitConverter.ToUInt32(wBytes.GetItems(4), 0);
-                vin[nIndex].scriptSig = new CScript(wBytes.GetItems((int)VarInt.ReadVarInt(ref wBytes)));
-                vin[nIndex].nSequence = BitConverter.ToUInt32(wBytes.GetItems(4), 0);
+                // Get amount
+                int nInputs = (int)wBytes.GetVarInt();
+                var vin = new CTxIn[nInputs];
+
+                for (int nIndex = 0; nIndex < nInputs; nIndex++)
+                {
+                    // Fill inputs array
+                    vin[nIndex] = new CTxIn();
+                    vin[nIndex].prevout = new COutPoint(wBytes.Get(36));
+                    vin[nIndex].scriptSig = new CScript(wBytes.Get((int)wBytes.GetVarInt()));
+                    vin[nIndex].nSequence = BitConverter.ToUInt32(wBytes.Get(4), 0);
+                }
+
+                // Return inputs array
+                return vin;
+            }
+            catch (Exception e)
+            {
+                throw new TxInConstructorException("Desirealization failed.", e);
             }
+        }
 
-            // Return inputs array
-            return vin;
+        /// <summary>
+        /// Serialized size
+        /// </summary>
+        public int Size
+        {
+            get {
+                int nSize = 40; // COutPoint, nSequence
+                nSize += VarInt.GetEncodedSize(scriptSig.Size);
+                nSize += scriptSig.Size;
+
+                return nSize;
+            }
         }
 
         /// <summary>
         /// Get raw bytes representation of our input.
         /// </summary>
         /// <returns>Byte sequence.</returns>
-        public IList<byte> Bytes
+        public static implicit operator byte[] (CTxIn input)
         {
-            get
-            {
-                List<byte> inputBytes = new List<byte>();
-
-                inputBytes.AddRange(txID.hashBytes); // Input transaction id
-                inputBytes.AddRange(BitConverter.GetBytes(n)); // Output number
+            var stream = new MemoryStream();
+            var writer = new BinaryWriter(stream);
 
-                List<byte> s = new List<byte>(scriptSig.Bytes);
+            writer.Write(input.prevout); // prevout
+            writer.Write(VarInt.EncodeVarInt(input.scriptSig.Size)); // scriptSig length
+            writer.Write(input.scriptSig); // scriptSig
+            writer.Write(input.nSequence); // nSequence
 
-                inputBytes.AddRange(VarInt.EncodeVarInt(s.Count)); // scriptSig length
-                inputBytes.AddRange(s); // scriptSig
-                inputBytes.AddRange(BitConverter.GetBytes(nSequence)); // Sequence
-
-                return inputBytes;
-            }
+            var inputBytes = stream.ToArray();
+            writer.Close();
+            return inputBytes;
         }
 
-        public bool IsCoinBase
+        public bool IsFinal
         {
-            get { return txID.IsZero; }
+            get { return (nSequence == uint.MaxValue); }
         }
-
-               public override string ToString ()
+        public override string ToString ()
                {
                        StringBuilder sb = new StringBuilder ();
 
-            if (IsCoinBase)
+            sb.AppendFormat("CTxIn(");
+            sb.Append(prevout.ToString());
+
+            if(prevout.IsNull)
             {
-                sb.AppendFormat("CTxIn(txId={0}, coinbase={2}, nSequence={3})", txID.ToString(), n, Interop.ToHex(scriptSig.Bytes), nSequence);
+                sb.AppendFormat(", coinbase={0}", Interop.ToHex((byte[])scriptSig));
             }
             else
             {
-                sb.AppendFormat("CTxIn(txId={0}, n={1}, scriptSig={2}, nSequence={3})", txID.ToString(), n, scriptSig.ToString(), nSequence);
+                sb.AppendFormat(", scriptsig={0}", scriptSig.ToString());
+            }
+
+            if (nSequence != uint.MaxValue)
+            {
+                sb.AppendFormat(", nSequence={0}", nSequence);
             }
 
-                       return sb.ToString ();
+            sb.Append(")");
+
+
+            return sb.ToString ();
                }
 
        }
 }
-