Use byte[] instead of IEnumerable<byte> if possible
[NovacoinLibrary.git] / Novacoin / CTransaction.cs
index 89c4b11..3557398 100644 (file)
@@ -1,44 +1,67 @@
-\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;
 
 namespace Novacoin
 {
-       /// <summary>
-       /// Represents the transaction. Any transaction must provide one input and one output at least.
-       /// </summary>
-       public class CTransaction
-       {
-               /// <summary>
-               /// Version of transaction schema.
-               /// </summary>
-               public uint nVersion = 1;
-
-               /// <summary>
-               /// Transaction timestamp.
-               /// </summary>
-               public uint nTime = 0;
-
-               /// <summary>
-               /// Array of transaction inputs
-               /// </summary>
-               public CTxIn[] vin;
-
-               /// <summary>
-               /// Array of transaction outputs
-               /// </summary>
-               public CTxOut[] vout;
-
-               /// <summary>
-               /// Block height or timestamp when transaction is final
-               /// </summary>
-               public uint nLockTime = 0;
+    /// <summary>
+    /// Represents the transaction. Any transaction must provide one input and one output at least.
+    /// </summary>
+    public class CTransaction
+    {
+        /// <summary>
+        /// Version of transaction schema.
+        /// </summary>
+        public uint nVersion = 1;
+
+        /// <summary>
+        /// Transaction timestamp.
+        /// </summary>
+        public uint nTime = 0;
+
+        /// <summary>
+        /// Array of transaction inputs
+        /// </summary>
+        public CTxIn[] vin;
+
+        /// <summary>
+        /// Array of transaction outputs
+        /// </summary>
+        public CTxOut[] vout;
+
+        /// <summary>
+        /// Block height or timestamp when transaction is final
+        /// </summary>
+        public uint nLockTime = 0;
 
         /// <summary>
         /// Initialize an empty instance
         /// </summary>
         public CTransaction()
         {
+            // Initialize empty input and output arrays. Please note that such 
+            // configuration is not valid for real transaction, you have to supply 
+            // at least one input and one output.
+            vin = new CTxIn[0];
+            vout = new CTxOut[0];
         }
 
         /// <summary>
@@ -72,65 +95,63 @@ namespace Novacoin
         /// Parse byte sequence and initialize new instance of CTransaction
         /// </summary>
         /// <param name="txBytes">Byte sequence</param>
-               public CTransaction (IList<byte> txBytes)
-               {
-            WrappedList<byte> wBytes = new WrappedList<byte>(txBytes);
+               public CTransaction(IList<byte> txBytes)
+        {
+            var wBytes = new ByteQueue(txBytes);
 
-            nVersion = BitConverter.ToUInt32(wBytes.GetItems(4),0);
-            nTime = BitConverter.ToUInt32(wBytes.GetItems(4),0);
+            nVersion = BitConverter.ToUInt32(wBytes.Get(4), 0);
+            nTime = BitConverter.ToUInt32(wBytes.Get(4), 0);
 
-            int nInputs = (int)VarInt.ReadVarInt(ref wBytes);
+            int nInputs = (int)(int)wBytes.GetVarInt();
             vin = new CTxIn[nInputs];
 
             for (int nCurrentInput = 0; nCurrentInput < nInputs; nCurrentInput++)
             {
                 // Fill inputs array
                 vin[nCurrentInput] = new CTxIn();
+                
+                vin[nCurrentInput].prevout = new COutPoint(wBytes.Get(36));
 
-                vin[nCurrentInput].txID = new Hash256(wBytes.GetItems(32));
-                vin[nCurrentInput].n = BitConverter.ToUInt32(wBytes.GetItems(4), 0);
+                int nScriptSigLen = (int)wBytes.GetVarInt();
+                vin[nCurrentInput].scriptSig = new CScript(wBytes.Get(nScriptSigLen));
 
-                int nScriptSigLen = (int)VarInt.ReadVarInt(ref wBytes);
-                vin[nCurrentInput].scriptSig = new CScript(wBytes.GetItems(nScriptSigLen));
-                vin[nCurrentInput].nSequence = BitConverter.ToUInt32(wBytes.GetItems(4), 0);
+                vin[nCurrentInput].nSequence = BitConverter.ToUInt32(wBytes.Get(4), 0);
             }
 
-            int nOutputs = (int)VarInt.ReadVarInt(ref wBytes);
+            int nOutputs = (int)wBytes.GetVarInt();
             vout = new CTxOut[nOutputs];
 
             for (int nCurrentOutput = 0; nCurrentOutput < nOutputs; nCurrentOutput++)
             {
                 // Fill outputs array
                 vout[nCurrentOutput] = new CTxOut();
-                vout[nCurrentOutput].nValue = BitConverter.ToUInt64(wBytes.GetItems(8), 0);
+                vout[nCurrentOutput].nValue = BitConverter.ToInt64(wBytes.Get(8), 0);
 
-                int nScriptPKLen = (int)VarInt.ReadVarInt(ref wBytes);
-                vout[nCurrentOutput].scriptPubKey = new CScript(wBytes.GetItems(nScriptPKLen));
+                int nScriptPKLen = (int)wBytes.GetVarInt();
+                vout[nCurrentOutput].scriptPubKey = new CScript(wBytes.Get(nScriptPKLen));
             }
 
-            nLockTime = BitConverter.ToUInt32(wBytes.GetItems(4), 0);
-               }
+            nLockTime = BitConverter.ToUInt32(wBytes.Get(4), 0);
+        }
 
         /// <summary>
         /// Read transactions array which is encoded in the block body.
         /// </summary>
         /// <param name="wTxBytes">Bytes sequence</param>
         /// <returns>Transactions array</returns>
-        public static CTransaction[] ReadTransactionsList(ref WrappedList<byte> wTxBytes)
+        public static CTransaction[] ReadTransactionsList(ref ByteQueue wTxBytes)
         {
-            CTransaction[] tx;
-            
             // Read amount of transactions
-            int nTransactions = (int) VarInt.ReadVarInt(ref wTxBytes);
-            tx = new CTransaction[nTransactions];
+            int nTransactions = (int)wTxBytes.GetVarInt();
+            var tx = new CTransaction[nTransactions];
 
             for (int nTx = 0; nTx < nTransactions; nTx++)
             {
                 // Fill the transactions array
                 tx[nTx] = new CTransaction();
 
-                tx[nTx].nVersion = BitConverter.ToUInt32(wTxBytes.GetItems(4), 0);
-                tx[nTx].nTime = BitConverter.ToUInt32(wTxBytes.GetItems(4), 0);
+                tx[nTx].nVersion = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
+                tx[nTx].nTime = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
 
                 // Inputs array
                 tx[nTx].vin = CTxIn.ReadTxInList(ref wTxBytes);
@@ -138,17 +159,41 @@ namespace Novacoin
                 // outputs array
                 tx[nTx].vout = CTxOut.ReadTxOutList(ref wTxBytes);
 
-                tx[nTx].nLockTime = BitConverter.ToUInt32(wTxBytes.GetItems(4), 0);
+                tx[nTx].nLockTime = BitConverter.ToUInt32(wTxBytes.Get(4), 0);
             }
 
             return tx;
         }
 
+        public bool IsCoinBase
+        {
+            get { return (vin.Length == 1 && vin[0].prevout.IsNull && vout.Length >= 1); }
+        }
+
+        public bool IsCoinStake
+        {
+            get
+            {
+                return (vin.Length > 0 && (!vin[0].prevout.IsNull) && vout.Length >= 2 && vout[0].IsEmpty);
+            }
+        }
+
+        /// <summary>
+        /// Transaction hash
+        /// </summary>
+        public Hash256 Hash
+        {
+            get { return Hash256.Compute256(Bytes); }
+        }
+
+        /// <summary>
+        /// A sequence of bytes, which corresponds to the current state of CTransaction.
+        /// </summary>
         public IList<byte> Bytes
         {
             get
             {
-                List<byte> resultBytes = new List<byte>();
+                var resultBytes = new List<byte>();
 
                 // Typical transaction example:
                 //
@@ -198,14 +243,14 @@ namespace Novacoin
                 resultBytes.AddRange(BitConverter.GetBytes(nTime));
                 resultBytes.AddRange(VarInt.EncodeVarInt(vin.LongLength));
 
-                foreach (CTxIn input in vin)
+                foreach (var input in vin)
                 {
                     resultBytes.AddRange(input.Bytes);
                 }
 
                 resultBytes.AddRange(VarInt.EncodeVarInt(vout.LongLength));
 
-                foreach (CTxOut output in vout)
+                foreach (var output in vout)
                 {
                     resultBytes.AddRange(output.Bytes);
                 }
@@ -218,16 +263,16 @@ namespace Novacoin
 
         public override string ToString()
         {
-            StringBuilder sb = new StringBuilder();
+            var sb = new StringBuilder();
 
             sb.AppendFormat("CTransaction(\n nVersion={0},\n nTime={1},\n", nVersion, nTime);
 
-            foreach (CTxIn txin in vin)
+            foreach (var txin in vin)
             {
                 sb.AppendFormat(" {0},\n", txin.ToString());
             }
 
-            foreach (CTxOut txout in vout)
+            foreach (var txout in vout)
             {
                 sb.AppendFormat(" {0},\n", txout.ToString());
             }