CTxIn and CTxOut constructors, some interoperability improvements
authorCryptoManiac <balthazar@yandex.ru>
Sun, 16 Aug 2015 22:00:32 +0000 (01:00 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Sun, 16 Aug 2015 22:00:32 +0000 (01:00 +0300)
Novacoin/CTxIn.cs
Novacoin/CTxOut.cs
Novacoin/Interop.cs
Novacoin/VarInt.cs

index c3b2fc5..b87e594 100644 (file)
@@ -29,15 +29,41 @@ namespace Novacoin
                /// </summary>
                private uint nSequence = 0xffffffff;
 
-               public CTxIn ()
+        /// <summary>
+        /// Initialize new CTxIn instance as copy of another one.
+        /// </summary>
+        /// <param name="i">CTxIn instance.</param>
+        public CTxIn(CTxIn i)
+        {
+            txID = i.txID;
+            nInput = i.nInput;
+            scriptSig = i.scriptSig;
+            nSequence = i.nSequence;
+        }
+
+        /// <summary>
+        /// Decode byte sequence and initialize new instance of CTxIn class.
+        /// </summary>
+        /// <param name="bytes">Byte sequence</param>
+               public CTxIn (IList<byte> bytes)
                {
+            WrappedList<byte> wBytes = new WrappedList<byte>(bytes);
+
+            txID = new Hash256(wBytes.GetItems(32));
+            nInput = Interop.LEBytesToUInt32(wBytes.GetItems(4));
+            int ssLength = (int)VarInt.ReadVarInt(wBytes);
+            scriptSig = wBytes.GetItems(ssLength);
+            nSequence = Interop.LEBytesToUInt32(wBytes.GetItems(4));
                }
 
+        /// <summary>
+        /// Get raw bytes representation of our input.
+        /// </summary>
+        /// <returns>Byte sequence.</returns>
         public IList<byte> ToBytes()
         {
             List<byte> inputBytes = new List<byte>();
 
-
             inputBytes.AddRange(txID.hashBytes); // Input transaction id
             inputBytes.AddRange(Interop.LEBytes(nInput)); // Input number
             inputBytes.AddRange(VarInt.EncodeVarInt(scriptSig.LongLength)); // Scriptsig length
index 679c692..42d2b8d 100644 (file)
@@ -12,17 +12,41 @@ namespace Novacoin
                /// <summary>
                /// Input value.
                /// </summary>
-               private ulong nValue = 0;
+               private ulong nValue;
 
                /// <summary>
                /// Second half of script which contains spending instructions.
                /// </summary>
                private byte[] scriptPubKey;
 
-               public CTxOut ()
-               {
-               }
+        /// <summary>
+        /// Initialize new CTxOut instance as a copy of another instance.
+        /// </summary>
+        /// <param name="o">CTxOut instance.</param>
+        public CTxOut(CTxOut o)
+        {
+            nValue = o.nValue;
+            scriptPubKey = o.scriptPubKey;
+        }
+
+        /// <summary>
+        /// Parse input byte sequence and initialize new CTxOut instance.
+        /// </summary>
+        /// <param name="bytes">Byte sequence.</param>
+        public CTxOut(IList<byte> bytes)
+        {
+            WrappedList<byte> wBytes = new WrappedList<byte>(bytes);
+            
+            nValue = Interop.LEBytesToUInt64(wBytes.GetItems(8));
+            int spkLength = (int)VarInt.ReadVarInt(wBytes);
+
+            scriptPubKey = wBytes.GetItems(spkLength);
+        }
 
+        /// <summary>
+        /// Get raw bytes representation of our output.
+        /// </summary>
+        /// <returns>Byte sequence.</returns>
         public IList<byte> ToBytes()
         {
             List<byte> resultBytes = new List<byte>();
index 149774e..1008392 100644 (file)
@@ -6,6 +6,23 @@ using System.Threading.Tasks;
 
 namespace Novacoin
 {
+    public class InteropException : Exception
+    {
+        public InteropException()
+        {
+        }
+
+        public InteropException(string message)
+            : base(message)
+        {
+        }
+
+        public InteropException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+
     class Interop
     {
         public static byte[] LEBytes(ushort n)
@@ -80,5 +97,51 @@ namespace Novacoin
             return resultBytes;
         }
 
+        public static ushort LEBytesToUInt16(byte[] bytes)
+        {
+            if (bytes.Length != sizeof(ushort))
+            {
+                throw new InteropException("Array size doesn't match the ushort data type.");
+            }
+
+            if (!BitConverter.IsLittleEndian)
+            {
+                Array.Reverse(bytes);
+            }
+
+            return BitConverter.ToUInt16(bytes, 0);
+        }
+
+        public static uint LEBytesToUInt32(byte[] bytes)
+        {
+            if (bytes.Length != sizeof(ushort))
+            {
+                throw new InteropException("Array size doesn't match the uint data type.");
+            }
+
+            if (!BitConverter.IsLittleEndian)
+            {
+                Array.Reverse(bytes);
+            }
+
+            return BitConverter.ToUInt32(bytes, 0);
+        }
+
+        public static ulong LEBytesToUInt64(byte[] bytes)
+        {
+            if (bytes.Length != sizeof(ushort))
+            {
+                throw new InteropException("Array size doesn't match the ulong data type.");
+            }
+
+            if (!BitConverter.IsLittleEndian)
+            {
+                Array.Reverse(bytes);
+            }
+
+            return BitConverter.ToUInt64(bytes, 0);
+        }
+
+
     }
 }
index 7e0afb7..d4c3168 100644 (file)
@@ -79,25 +79,69 @@ namespace Novacoin
             byte prefix = bytes[0];
 
             bytes.RemoveAt(0); // Remove prefix
+
             byte[] bytesArray = bytes.ToArray();
 
-            if (!BitConverter.IsLittleEndian)
+            if (BitConverter.IsLittleEndian)
+            {
+                switch (prefix)
+                {
+                    case 0xfd: // ushort flag
+                        return BitConverter.ToUInt16(bytesArray, 0);
+                    case 0xfe: // uint flag
+                        return BitConverter.ToUInt32(bytesArray, 0);
+                    case 0xff: // ulong flag
+                        return BitConverter.ToUInt64(bytesArray, 0);
+                    default:
+                        return prefix;
+                }
+            }
+            else
             {
                 // Values are stored in little-endian order
-                Array.Reverse(bytesArray);
+                switch (prefix)
+                {
+                    case 0xfd: // ushort flag
+                        Array.Resize<byte>(ref bytesArray, 2);
+                        Array.Reverse(bytesArray);
+                        return BitConverter.ToUInt16(bytesArray, 0);
+                    case 0xfe: // uint flag
+                        Array.Resize<byte>(ref bytesArray, 4);
+                        Array.Reverse(bytesArray);
+                        return BitConverter.ToUInt32(bytesArray, 0);
+                    case 0xff: // ulong flag
+                        Array.Resize<byte>(ref bytesArray, 8);
+                        Array.Reverse(bytesArray);
+                        return BitConverter.ToUInt64(bytesArray, 0);
+                    default:
+                        return prefix;
+                }
             }
+        }
+
+        /// <summary>
+        /// Read and decode variable integer from wrapped list object.
+        /// 
+        /// Note: Should be used only if there is some variable integer data at current position. Otherwise you will get undefined behavior, so make sure that you know what you are doing.
+        /// </summary>
+        /// <param name="wBytes"></param>
+        /// <returns></returns>
+        public static ulong ReadVarInt(WrappedList<byte> wBytes)
+        {
+            byte prefix = wBytes.GetItem();
 
             switch (prefix)
             {
-                case 0xfd: // ushort flag
-                    return BitConverter.ToUInt16(bytesArray, 0);
-                case 0xfe: // uint flag
-                    return BitConverter.ToUInt32(bytesArray, 0);
-                case 0xff: // ulong flag
-                    return BitConverter.ToUInt64(bytesArray, 0);
+                case 0xfd: // ushort
+                    return Interop.LEBytesToUInt16(wBytes.GetItems(2));
+                case 0xfe: // uint
+                    return Interop.LEBytesToUInt32(wBytes.GetItems(4));
+                case 0xff: // ulong
+                    return Interop.LEBytesToUInt64(wBytes.GetItems(8));
                 default:
                     return prefix;
             }
+
         }
     }
 }