/// </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
/// <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>();
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)
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);
+ }
+
+
}
}
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;
}
+
}
}
}