From be9d844557911f95165d2c9875c4f5b2822cfc92 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Mon, 31 Aug 2015 19:24:53 +0300 Subject: [PATCH] Turn ByteQueue into MemoryStream wrapper, use MemoryStream for serialization of COutPoint/CTxIn/CTxOut/CTransaction objects. --- Novacoin/ByteQueue.cs | 141 +++++++++++++++++++++++---------------------- Novacoin/CBlock.cs | 6 +- Novacoin/CBlockStore.cs | 22 +++---- Novacoin/COutPoint.cs | 15 ++++- Novacoin/CPubKey.cs | 2 +- Novacoin/CScript.cs | 14 ++-- Novacoin/CTransaction.cs | 32 +++++++---- Novacoin/CTxIn.cs | 20 ++++--- Novacoin/CTxOut.cs | 16 +++-- Novacoin/NetInfo.cs | 25 ++++++++ Novacoin/Novacoin.csproj | 2 +- Novacoin/VarInt.cs | 19 ++++++ 12 files changed, 189 insertions(+), 125 deletions(-) create mode 100644 Novacoin/NetInfo.cs diff --git a/Novacoin/ByteQueue.cs b/Novacoin/ByteQueue.cs index 9752c02..8af351f 100644 --- a/Novacoin/ByteQueue.cs +++ b/Novacoin/ByteQueue.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using System.IO; namespace Novacoin { @@ -45,104 +46,97 @@ namespace Novacoin /// /// TODO: rewrite using MemoryStream /// - public class ByteQueue + public class ByteQueue : IDisposable { - private int _Index; - private List _Elements; + private bool disposed = false; - public ByteQueue(byte[] List, int Start) + private MemoryStream _Stream; + private BinaryReader _Reader; + + public ByteQueue(ref byte[] buffer, int Start) { - _Elements = new List(List); - _Index = Start; + _Stream = new MemoryStream(buffer); + _Stream.Seek(Start, SeekOrigin.Begin); + _Reader = new BinaryReader(_Stream); } - public ByteQueue(byte[] List) + public ByteQueue(ref byte[] buffer) { - _Elements = new List(List); - _Index = 0; + _Stream = new MemoryStream(buffer); + _Reader = new BinaryReader(_Stream); } - public ByteQueue(List List, int Start) + public ByteQueue(ref List List, int Start) { - _Elements = new List(List); - _Index = Start; + _Stream = new MemoryStream(List.ToArray()); + _Stream.Seek(Start, SeekOrigin.Begin); + _Reader = new BinaryReader(_Stream); } - public ByteQueue(List List) + public ByteQueue(ref List List) { - _Elements = new List(List); - _Index = 0; + _Stream = new MemoryStream(List.ToArray()); + _Reader = new BinaryReader(_Stream); } - public byte Get() + ~ByteQueue() { - if (_Elements.Count <= _Index) - { - throw new ByteQueueException("No elements left."); - } - - return _Elements[_Index++]; + Dispose(false); } - public bool TryGet(ref byte Element) + public void Dispose() { - if (_Elements.Count <= _Index) - { - return false; - } - - Element = _Elements[_Index++]; - - return true; + Dispose(true); + GC.SuppressFinalize(this); } - public byte GetCurrent() + protected virtual void Dispose(bool disposing) { - return _Elements[_Index]; + if (!disposed) + { + if (disposing) + { + _Reader.Dispose(); + _Stream.Dispose(); + } + + disposed = true; + } } - public byte[] Get(int nCount) + public byte Get() { - Contract.Requires(Count - Index >= nCount, "nCount is greater than amount of elements."); - - var result = _Elements.GetRange(_Index, nCount).ToArray(); - _Index += nCount; + if (_Stream.Position == _Stream.Length) + { + throw new ByteQueueException("No elements left."); + } - return result; + return _Reader.ReadByte(); } - public bool TryGet(int nCount, ref byte[] Elements) + public bool TryGet(ref byte Element) { - if (Count - Index < nCount) + if (_Stream.Position == _Stream.Length) { return false; } - Elements = _Elements.GetRange(_Index, nCount).ToArray(); - _Index += nCount; + Element = _Reader.ReadByte(); return true; } - public byte[] GetCurrent(int nCount) + public byte[] Get(int nCount) { Contract.Requires(Count - Index >= nCount, "nCount is greater than amount of elements."); - var result = _Elements.GetRange(_Index, nCount).ToArray(); - - return result; + return _Reader.ReadBytes(nCount); } - public bool TryGetCurrent(int nCount, ref byte[] Elements) + public bool TryGet(int nCount, ref byte[] Elements) { - if (Count - Index < nCount) - { - return false; - } - - Elements = _Elements.GetRange(_Index, nCount).ToArray(); - - return true; + Elements = _Reader.ReadBytes(nCount); + return (Elements.Length == nCount); } /// @@ -150,29 +144,38 @@ namespace Novacoin /// public int Index { - get { return _Index; } + get { return (int)_Stream.Position; } } public int Count { - get { return _Elements.Count; } + get { return (int)_Stream.Length; } } public ulong GetVarInt() { - byte prefix = Get(); - - switch (prefix) + try { - case 0xfd: // ushort - return BitConverter.ToUInt16(Get(2), 0); - case 0xfe: // uint - return BitConverter.ToUInt32(Get(4), 0); - case 0xff: // ulong - return BitConverter.ToUInt64(Get(8), 0); - default: - return prefix; + byte prefix = _Reader.ReadByte(); + + switch (prefix) + { + case 0xfd: // ushort + return _Reader.ReadUInt16(); + case 0xfe: // uint + return _Reader.ReadUInt32(); + case 0xff: // ulong + return _Reader.ReadUInt64(); + default: + return prefix; + } + } + catch (EndOfStreamException e) + { + throw new ByteQueueException("No elements left.", e); } } } } + + diff --git a/Novacoin/CBlock.cs b/Novacoin/CBlock.cs index 30350b7..4c87806 100644 --- a/Novacoin/CBlock.cs +++ b/Novacoin/CBlock.cs @@ -87,7 +87,7 @@ namespace Novacoin { try { - ByteQueue wBytes = new ByteQueue(blockBytes); + ByteQueue wBytes = new ByteQueue(ref blockBytes); // Fill the block header fields header = new CBlockHeader(wBytes.Get(80)); @@ -185,13 +185,13 @@ namespace Novacoin } // Check timestamp - if (header.nTime > NetInfo.FutureDrift(NetInfo.GetAdjustedTime())) + if (header.nTime > NetUtils.FutureDrift(NetUtils.GetAdjustedTime())) { return false; } // Check coinbase timestamp - if (header.nTime < NetInfo.PastDrift(vtx[0].nTime)) + if (header.nTime < NetUtils.PastDrift(vtx[0].nTime)) { return false; } diff --git a/Novacoin/CBlockStore.cs b/Novacoin/CBlockStore.cs index 8d77dc4..2c43d65 100644 --- a/Novacoin/CBlockStore.cs +++ b/Novacoin/CBlockStore.cs @@ -189,13 +189,13 @@ namespace Novacoin // Seek to the end and then append magic bytes there. writer.Seek(0, SeekOrigin.End); writer.Write(magicBytes, 0, magicBytes.Length); - writer.Write(blkLenBytes, 0, blkLenBytes.Length); // Save block size and current position in the block cursor fields. nBlockPos = writer.Position; nBlockSize = blockBytes.Length; // Write block and flush the stream. + writer.Write(blkLenBytes, 0, blkLenBytes.Length); writer.Write(blockBytes, 0, blockBytes.Length); writer.Flush(); @@ -369,12 +369,7 @@ namespace Novacoin /// /// Block file stream with read access /// - private Stream reader; - - /// - /// Block file stream with write access - /// - private Stream writer; + private Stream fStreamReadWrite; /// /// Init the block storage manager. @@ -389,9 +384,7 @@ namespace Novacoin bool firstInit = !File.Exists(strDbFile); dbConn = new SQLiteConnection(new SQLitePlatformGeneric(), strDbFile); - var fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); - reader = new BinaryReader(fStreamReadWrite).BaseStream; - writer = new BinaryWriter(fStreamReadWrite).BaseStream; + fStreamReadWrite = File.Open(strBlockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite); if (firstInit) { @@ -431,6 +424,7 @@ namespace Novacoin public bool GetTransaction(Hash256 TxID, ref CTransaction tx) { + var reader = new BinaryReader(fStreamReadWrite).BaseStream; var QueryTx = dbConn.Query("select * from [TransactionStorage] where [TransactionHash] = ?", (byte[])TxID); if (QueryTx.Count == 1) @@ -445,6 +439,7 @@ namespace Novacoin private bool AddItemToIndex(ref CBlockStoreItem itemTemplate, ref CBlock block) { + var writer = new BinaryWriter(fStreamReadWrite).BaseStream; var blockHash = new ScryptHash256(itemTemplate.Hash); if (blockMap.ContainsKey(blockHash)) @@ -527,7 +522,7 @@ namespace Novacoin uint nHeight = prevBlockCursor.nHeight + 1; // Check timestamp against prev - if (NetInfo.FutureDrift(block.header.nTime) < prevBlockHeader.nTime) + if (NetUtils.FutureDrift(block.header.nTime) < prevBlockHeader.nTime) { // block's timestamp is too early return false; @@ -562,6 +557,8 @@ namespace Novacoin public bool GetBlock(ScryptHash256 blockHash, ref CBlock block) { + var reader = new BinaryReader(fStreamReadWrite).BaseStream; + var QueryBlock = dbConn.Query("select * from [BlockStorage] where [Hash] = ?", (byte[])blockHash); if (QueryBlock.Count == 1) @@ -747,8 +744,7 @@ namespace Novacoin { // Free other state (managed objects). - reader.Dispose(); - reader.Dispose(); + fStreamReadWrite.Dispose(); } if (dbConn != null) diff --git a/Novacoin/COutPoint.cs b/Novacoin/COutPoint.cs index a9a347c..ddb40e8 100644 --- a/Novacoin/COutPoint.cs +++ b/Novacoin/COutPoint.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; +using System.IO; using System.Text; namespace Novacoin @@ -73,11 +74,17 @@ namespace Novacoin public static implicit operator byte[] (COutPoint o) { - var r = new List(); - r.AddRange((byte[])o.hash); - r.AddRange(BitConverter.GetBytes(o.n)); + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); - return r.ToArray(); + writer.Write(o.hash); + writer.Write(o.n); + + var outBytes = stream.ToArray(); + + writer.Close(); + + return outBytes; } public override string ToString() diff --git a/Novacoin/CPubKey.cs b/Novacoin/CPubKey.cs index 6d8b2d3..33d1b92 100644 --- a/Novacoin/CPubKey.cs +++ b/Novacoin/CPubKey.cs @@ -67,7 +67,7 @@ namespace Novacoin public string ToHex() { - return Interop.ToHex((byte[])this); + return Interop.ToHex(this); } /// diff --git a/Novacoin/CScript.cs b/Novacoin/CScript.cs index 8757bb7..229b60b 100644 --- a/Novacoin/CScript.cs +++ b/Novacoin/CScript.cs @@ -54,7 +54,7 @@ namespace Novacoin /// public ByteQueue GetByteQueue() { - return new ByteQueue(codeBytes); + return new ByteQueue(ref codeBytes); } /// @@ -157,7 +157,7 @@ namespace Novacoin } var count = 0; - var bq1 = new ByteQueue(codeBytes); + var bq1 = new ByteQueue(ref codeBytes); byte[] pushData; instruction opcode; @@ -203,7 +203,7 @@ namespace Novacoin var count = 0; var newScript = new CScript(); - var bq1 = new ByteQueue(codeBytes); + var bq1 = new ByteQueue(ref codeBytes); while (ScriptCode.GetOp(ref bq1, out opcode, out pushData)) { @@ -239,7 +239,7 @@ namespace Novacoin { get { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument @@ -265,7 +265,7 @@ namespace Novacoin { get { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); byte[] pushArgs; // OP_PUSHDATAn argument instruction opcode; // Current instruction @@ -354,7 +354,7 @@ namespace Novacoin /// Amount of sigops public uint GetSigOpCount(bool fAccurate) { - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument @@ -520,7 +520,7 @@ namespace Novacoin public override string ToString() { var sb = new StringBuilder(); - var wCodeBytes = new ByteQueue(codeBytes); + var wCodeBytes = new ByteQueue(ref codeBytes); instruction opcode; // Current instruction byte[] pushArgs; // OP_PUSHDATAn argument diff --git a/Novacoin/CTransaction.cs b/Novacoin/CTransaction.cs index 83d2a09..979b689 100644 --- a/Novacoin/CTransaction.cs +++ b/Novacoin/CTransaction.cs @@ -19,6 +19,7 @@ using System; using System.Text; using System.Collections.Generic; +using System.IO; namespace Novacoin { @@ -244,9 +245,9 @@ namespace Novacoin } if (nBlockTime == 0) { - nBlockTime = NetInfo.GetAdjustedTime(); + nBlockTime = NetUtils.GetAdjustedTime(); } - if (nLockTime < (nLockTime < NetInfo.nLockTimeThreshold ? nBlockHeight : nBlockTime)) + if (nLockTime < (nLockTime < NetUtils.nLockTimeThreshold ? nBlockHeight : nBlockTime)) { return true; } @@ -268,7 +269,7 @@ namespace Novacoin { try { - var wBytes = new ByteQueue(txBytes); + var wBytes = new ByteQueue(ref txBytes); nVersion = BitConverter.ToUInt32(wBytes.Get(4), 0); nTime = BitConverter.ToUInt32(wBytes.Get(4), 0); @@ -401,29 +402,36 @@ namespace Novacoin /// public static implicit operator byte[] (CTransaction tx) { - var resultBytes = new List(); + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); - resultBytes.AddRange(BitConverter.GetBytes(tx.nVersion)); - resultBytes.AddRange(BitConverter.GetBytes(tx.nTime)); - resultBytes.AddRange(VarInt.EncodeVarInt(tx.vin.LongLength)); + writer.Write(tx.nVersion); + writer.Write(tx.nTime); + writer.Write(VarInt.EncodeVarInt(tx.vin.LongLength)); foreach (var input in tx.vin) { - resultBytes.AddRange((byte[])input); + writer.Write(input); } - resultBytes.AddRange(VarInt.EncodeVarInt(tx.vout.LongLength)); + writer.Write(VarInt.EncodeVarInt(tx.vout.LongLength)); foreach (var output in tx.vout) { - resultBytes.AddRange((byte[])output); + writer.Write(output); } - resultBytes.AddRange(BitConverter.GetBytes(tx.nLockTime)); + writer.Write(tx.nLockTime); - return resultBytes.ToArray(); + var resultBytes = stream.ToArray(); + + writer.Close(); + + return resultBytes; } + + public override string ToString() { var sb = new StringBuilder(); diff --git a/Novacoin/CTxIn.cs b/Novacoin/CTxIn.cs index af8539f..067ad46 100644 --- a/Novacoin/CTxIn.cs +++ b/Novacoin/CTxIn.cs @@ -19,6 +19,7 @@ using System; using System.Text; using System.Collections.Generic; +using System.IO; namespace Novacoin { @@ -131,18 +132,19 @@ namespace Novacoin /// Byte sequence. public static implicit operator byte[] (CTxIn input) { - var inputBytes = new List(); + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); - inputBytes.AddRange((byte[])input.prevout); // prevout + writer.Write(input.prevout); // prevout + writer.Write(VarInt.EncodeVarInt(input.scriptSig.Size)); // scriptSig length + writer.Write(input.scriptSig); // scriptSig + writer.Write(input.nSequence); // nSequence - var s = (byte[])input.scriptSig; - inputBytes.AddRange(VarInt.EncodeVarInt(s.Length)); // scriptSig length - inputBytes.AddRange(s); // scriptSig - inputBytes.AddRange(BitConverter.GetBytes(input.nSequence)); // Sequence - - return inputBytes.ToArray(); + var inputBytes = stream.ToArray(); + writer.Close(); + return inputBytes; } - + public bool IsFinal { get { return (nSequence == uint.MaxValue); } diff --git a/Novacoin/CTxOut.cs b/Novacoin/CTxOut.cs index 3f63423..eb24845 100644 --- a/Novacoin/CTxOut.cs +++ b/Novacoin/CTxOut.cs @@ -19,6 +19,7 @@ using System; using System.Text; using System.Collections.Generic; +using System.IO; namespace Novacoin { @@ -84,15 +85,18 @@ namespace Novacoin /// Byte sequence. public static implicit operator byte[] (CTxOut output) { - var resultBytes = new List(); + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); - resultBytes.AddRange(BitConverter.GetBytes(output.nValue)); // txout value + writer.Write(output.nValue); // txout value + writer.Write(VarInt.EncodeVarInt(output.scriptPubKey.Size)); // scriptPubKey length + writer.Write(output.scriptPubKey); // scriptPubKey - byte[] s = output.scriptPubKey; - resultBytes.AddRange(VarInt.EncodeVarInt(s.Length)); // scriptPubKey length - resultBytes.AddRange(s); // scriptPubKey + var resultBytes = stream.ToArray(); - return resultBytes.ToArray(); + writer.Close(); + + return resultBytes; } /// diff --git a/Novacoin/NetInfo.cs b/Novacoin/NetInfo.cs new file mode 100644 index 0000000..e0307bc --- /dev/null +++ b/Novacoin/NetInfo.cs @@ -0,0 +1,25 @@ +using System; + +namespace Novacoin +{ + internal class NetUtils + { + public static readonly uint nLockTimeThreshold = 500000000; + private static readonly uint nDrift = 7200; + + public static uint GetAdjustedTime() + { + return Interop.GetTime(); + } + + public static uint FutureDrift(uint nTime) + { + return nTime + nDrift; // up to 2 hours from the future + } + + public static uint PastDrift(uint nTime) + { + return nTime - nDrift; // up to 2 hours from the past + } + } +} \ No newline at end of file diff --git a/Novacoin/Novacoin.csproj b/Novacoin/Novacoin.csproj index c5cb553..c15b923 100644 --- a/Novacoin/Novacoin.csproj +++ b/Novacoin/Novacoin.csproj @@ -107,6 +107,7 @@ + @@ -125,7 +126,6 @@ - diff --git a/Novacoin/VarInt.cs b/Novacoin/VarInt.cs index e78d107..0f77b18 100644 --- a/Novacoin/VarInt.cs +++ b/Novacoin/VarInt.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.IO; namespace Novacoin { @@ -128,5 +129,23 @@ namespace Novacoin return prefix; } } + + public static ulong ReadVarInt(ref BinaryReader reader) + { + byte prefix = reader.ReadByte(); + + switch (prefix) + { + case 0xfd: // ushort + return reader.ReadUInt16(); + case 0xfe: // uint + return reader.ReadUInt32(); + case 0xff: // ulong + return reader.ReadUInt64(); + default: + return prefix; + } + } + } } -- 1.7.1