From: CryptoManiac Date: Sun, 16 Aug 2015 22:00:32 +0000 (+0300) Subject: CTxIn and CTxOut constructors, some interoperability improvements X-Git-Url: https://git.novaco.in/?a=commitdiff_plain;h=ef95ef3d18953e855090da131dfe3938860f397b;p=NovacoinLibrary.git CTxIn and CTxOut constructors, some interoperability improvements --- diff --git a/Novacoin/CTxIn.cs b/Novacoin/CTxIn.cs index c3b2fc5..b87e594 100644 --- a/Novacoin/CTxIn.cs +++ b/Novacoin/CTxIn.cs @@ -29,15 +29,41 @@ namespace Novacoin /// private uint nSequence = 0xffffffff; - public CTxIn () + /// + /// Initialize new CTxIn instance as copy of another one. + /// + /// CTxIn instance. + public CTxIn(CTxIn i) + { + txID = i.txID; + nInput = i.nInput; + scriptSig = i.scriptSig; + nSequence = i.nSequence; + } + + /// + /// Decode byte sequence and initialize new instance of CTxIn class. + /// + /// Byte sequence + public CTxIn (IList bytes) { + WrappedList wBytes = new WrappedList(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)); } + /// + /// Get raw bytes representation of our input. + /// + /// Byte sequence. public IList ToBytes() { List inputBytes = new List(); - inputBytes.AddRange(txID.hashBytes); // Input transaction id inputBytes.AddRange(Interop.LEBytes(nInput)); // Input number inputBytes.AddRange(VarInt.EncodeVarInt(scriptSig.LongLength)); // Scriptsig length diff --git a/Novacoin/CTxOut.cs b/Novacoin/CTxOut.cs index 679c692..42d2b8d 100644 --- a/Novacoin/CTxOut.cs +++ b/Novacoin/CTxOut.cs @@ -12,17 +12,41 @@ namespace Novacoin /// /// Input value. /// - private ulong nValue = 0; + private ulong nValue; /// /// Second half of script which contains spending instructions. /// private byte[] scriptPubKey; - public CTxOut () - { - } + /// + /// Initialize new CTxOut instance as a copy of another instance. + /// + /// CTxOut instance. + public CTxOut(CTxOut o) + { + nValue = o.nValue; + scriptPubKey = o.scriptPubKey; + } + + /// + /// Parse input byte sequence and initialize new CTxOut instance. + /// + /// Byte sequence. + public CTxOut(IList bytes) + { + WrappedList wBytes = new WrappedList(bytes); + + nValue = Interop.LEBytesToUInt64(wBytes.GetItems(8)); + int spkLength = (int)VarInt.ReadVarInt(wBytes); + + scriptPubKey = wBytes.GetItems(spkLength); + } + /// + /// Get raw bytes representation of our output. + /// + /// Byte sequence. public IList ToBytes() { List resultBytes = new List(); diff --git a/Novacoin/Interop.cs b/Novacoin/Interop.cs index 149774e..1008392 100644 --- a/Novacoin/Interop.cs +++ b/Novacoin/Interop.cs @@ -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); + } + + } } diff --git a/Novacoin/VarInt.cs b/Novacoin/VarInt.cs index 7e0afb7..d4c3168 100644 --- a/Novacoin/VarInt.cs +++ b/Novacoin/VarInt.cs @@ -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(ref bytesArray, 2); + Array.Reverse(bytesArray); + return BitConverter.ToUInt16(bytesArray, 0); + case 0xfe: // uint flag + Array.Resize(ref bytesArray, 4); + Array.Reverse(bytesArray); + return BitConverter.ToUInt32(bytesArray, 0); + case 0xff: // ulong flag + Array.Resize(ref bytesArray, 8); + Array.Reverse(bytesArray); + return BitConverter.ToUInt64(bytesArray, 0); + default: + return prefix; + } } + } + + /// + /// 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. + /// + /// + /// + public static ulong ReadVarInt(WrappedList 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; } + } } }