4 using System.Collections.Generic;
7 using SQLite.Net.Attributes;
8 using SQLite.Net.Interop;
9 using SQLite.Net.Platform.Generic;
16 PROOF_OF_WORK_MODIFIER,
18 PROOF_OF_STAKE_MODIFIER
21 [Table("BlockStorage")]
25 /// Item ID in the database
27 [PrimaryKey, AutoIncrement]
28 public int ItemID { get; set; }
31 /// PBKDF2+Salsa20 of block hash
34 public byte[] Hash { get; set; }
39 public byte[] NextHash { get; set; }
42 /// Serialized representation of block header
44 public byte[] BlockHeader { get; set; }
49 public BlockType BlockTypeFlag { get; set; }
52 /// Block position in file
54 public long nBlockPos { get; set; }
57 /// Block size in bytes
59 public int nBlockSize { get; set; }
65 public class CChainNode
75 public CBlockHeader blockHeader;
80 public BlockType blockType;
85 public ScryptHash256 hashNextBlock;
88 public class CBlockStore : IDisposable
90 private bool disposed = false;
91 private object LockObj = new object();
92 private SQLiteConnection dbConn = null;
94 private Dictionary<ScryptHash256, CChainNode> blockMap = new Dictionary<ScryptHash256, CChainNode>();
97 /// Init the block storage manager.
99 /// <param name="IndexDB">Path to index database</param>
100 /// <param name="BlockFile">Path to block file</param>
101 public CBlockStore(string IndexDB = "blockstore.dat", string BlockFile = "blk0001.dat")
103 bool firstInit = !File.Exists(IndexDB);
104 dbConn = new SQLiteConnection(new SQLitePlatformGeneric(), IndexDB);
110 dbConn.CreateTable<CBlockStoreItem>(CreateFlags.AutoIncPK);
115 var QueryGet = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] order by [ItemId] asc");
117 foreach (CBlockStoreItem si in QueryGet)
120 new ScryptHash256(si.Hash),
123 blockHeader = new CBlockHeader(si.BlockHeader),
124 blockType = si.BlockTypeFlag
130 public bool ParseBlockFile(string BlockFile = "bootstrap.dat")
132 // TODO: Rewrite completely.
134 var QueryGet = dbConn.Query<CBlockStoreItem>("select * from [BlockStorage] order by [ItemId] desc limit 1");
138 if (QueryGet.Count() == 1)
140 var res = QueryGet.First();
141 nOffset = res.nBlockPos + res.nBlockSize;
144 var fileReader = new BinaryReader(File.OpenRead(BlockFile));
145 var fileStream = fileReader.BaseStream;
147 var buffer = new byte[1000000]; // Max block size is 1Mb
148 var intBuffer = new byte[4];
150 fileStream.Seek(nOffset, SeekOrigin.Begin); // Seek to previous offset + previous block length
152 dbConn.BeginTransaction();
154 while (fileStream.Read(buffer, 0, 4) == 4) // Read magic number
156 var nMagic = BitConverter.ToUInt32(buffer, 0);
157 if (nMagic != 0xe5e9e8e4)
159 Console.WriteLine("Incorrect magic number.");
163 var nBytesRead = fileStream.Read(buffer, 0, 4);
166 Console.WriteLine("BLKSZ EOF");
170 var nBlockSize = BitConverter.ToInt32(buffer, 0);
172 nOffset = fileStream.Position;
174 nBytesRead = fileStream.Read(buffer, 0, nBlockSize);
176 if (nBytesRead == 0 || nBytesRead != nBlockSize)
178 Console.WriteLine("BLK EOF");
182 var block = new CBlock(buffer);
183 var headerHash = block.header.Hash;
185 if (nOffset % 1000 == 0) // Commit on each 1000th block
187 Console.WriteLine("Offset={0}, Hash: {1}", nOffset, headerHash);
189 dbConn.BeginTransaction();
192 if (blockMap.ContainsKey(headerHash))
194 Console.WriteLine("Duplicate block {0}", headerHash);
201 blockHeader = block.header,
202 blockType = block.IsProofOfStake ? BlockType.PROOF_OF_STAKE : BlockType.PROOF_OF_WORK
205 var result = dbConn.Insert(new CBlockStoreItem()
208 BlockHeader = block.header,
209 BlockTypeFlag = block.IsProofOfStake ? BlockType.PROOF_OF_STAKE : BlockType.PROOF_OF_WORK,
211 nBlockSize = nBlockSize
217 fileReader.Dispose();
227 public void Dispose()
230 GC.SuppressFinalize(this);
233 protected virtual void Dispose(bool disposing)
239 // Free other state (managed objects).