public override bool AddBlock(Block block) { lock (block_cache) { if (!block_cache.ContainsKey(block.Hash)) { block_cache.Add(block.Hash, block); } } lock (header_index) { if (block.Height - 1 >= header_index.Count) { return(false); } if (block.Height == header_index.Count) { if (VerifyBlocks && !block.Verify()) { return(false); } WriteBatch batch = new WriteBatch(); OnAddHeader(block.Header, batch); db.Write(WriteOptions.Default, batch); } if (block.Height < header_index.Count) { new_block_event.Set(); } } return(true); }
private void OnAddHeader(Block header) { if (header.PrevBlock == current_header_hash) { current_header_hash = header.Hash; header_index.Add(header.Hash); uint height = header_chain.Nodes[current_header_hash].Height; if (height % 2000 == 0) { WriteBatch batch = new WriteBatch(); while (height - 2000 > stored_header_count) { using (MemoryStream ms = new MemoryStream()) using (BinaryWriter w = new BinaryWriter(ms)) { w.Write(header_index.Skip((int)stored_header_count).Take(2000).Select(p => header_chain[p]).ToArray()); w.Flush(); batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_HeaderList).Add(stored_header_count), ms.ToArray()); } stored_header_count += 2000; } db.Write(WriteOptions.Default, batch); } } else { TreeNode <Block> main = header_chain.Leaves.OrderByDescending(p => p.Height).First(); if (main.Item.Hash != current_header_hash) { TreeNode <Block> fork = header_chain.Nodes[current_header_hash]; current_header_hash = main.Item.Hash; TreeNode <Block> common = header_chain.FindCommonNode(main, fork); header_index.RemoveRange((int)common.Height + 1, header_index.Count - (int)common.Height - 1); for (TreeNode <Block> i = main; i != common; i = i.Parent) { header_index.Insert((int)common.Height + 1, i.Item.Hash); } if (header_chain.Nodes[current_block_hash].Height > common.Height) { //Rollback(common.Item.Hash); throw new InvalidDataException("Unexpected Rollback"); } } } }
public LevelDBBlockchain(string path) { header_index.Add(GenesisBlock.Hash); Version version; Slice value; db = DB.Open(path, new Options { CreateIfMissing = true }); if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Version), out value) && Version.TryParse(value.ToString(), out version) && version >= Version.Parse("0.6.6043.32131")) { ReadOptions options = new ReadOptions { FillCache = false }; value = db.Get(options, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock)); UInt256 current_header_hash = new UInt256(value.ToArray().Take(32).ToArray()); this.current_block_height = value.ToArray().ToUInt32(32); uint current_header_height = current_block_height; if (db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentHeader), out value)) { current_header_hash = new UInt256(value.ToArray().Take(32).ToArray()); current_header_height = value.ToArray().ToUInt32(32); } foreach (UInt256 hash in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_HeaderHashList), (k, v) => { using (MemoryStream ms = new MemoryStream(v.ToArray(), false)) using (BinaryReader r = new BinaryReader(ms)) { return(new { Index = k.ToArray().ToUInt32(1), Hashes = r.ReadSerializableArray <UInt256>() }); } }).OrderBy(p => p.Index).SelectMany(p => p.Hashes).ToArray()) { if (!hash.Equals(GenesisBlock.Hash)) { header_index.Add(hash); } stored_header_count++; } if (stored_header_count == 0) { Header[] headers = db.Find(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Header), (k, v) => Header.FromTrimmedData(v.ToArray(), sizeof(long))).OrderBy(p => p.Height).ToArray(); for (int i = 1; i < headers.Length; i++) { header_index.Add(headers[i].Hash); } } else if (current_header_height >= stored_header_count) { for (UInt256 hash = current_header_hash; hash != header_index[(int)stored_header_count - 1];) { Header header = Header.FromTrimmedData(db.Get(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Header).Add(hash)).ToArray(), sizeof(long)); header_index.Insert((int)stored_header_count, hash); hash = header.PrevBlock; } } } else { WriteBatch batch = new WriteBatch(); ReadOptions options = new ReadOptions { FillCache = false }; using (Iterator it = db.NewIterator(options)) { for (it.SeekToFirst(); it.Valid(); it.Next()) { batch.Delete(it.Key()); } } db.Write(WriteOptions.Default, batch); Persist(GenesisBlock); db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Version), GetType().GetTypeInfo().Assembly.GetName().Version.ToString()); } thread_persistence = new Thread(PersistBlocks); thread_persistence.Name = "LevelDBBlockchain.PersistBlocks"; thread_persistence.Start(); }
public LevelDBBlockchain(string path) { header_index.Add(GenesisBlock.Hash); Version version; Slice value; db = DB.Open(path, new Options { CreateIfMissing = true }); if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Version), out value) && Version.TryParse(value.ToString(), out version) && version >= Version.Parse("0.5")) { ReadOptions options = new ReadOptions { FillCache = false }; value = db.Get(options, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock)); this.current_block_hash = new UInt256(value.ToArray().Take(32).ToArray()); this.current_block_height = BitConverter.ToUInt32(value.ToArray(), 32); foreach (Block header in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.DATA_HeaderList), (k, v) => { using (MemoryStream ms = new MemoryStream(v.ToArray(), false)) using (BinaryReader r = new BinaryReader(ms)) { return(new { Index = BitConverter.ToUInt32(k.ToArray(), 1), Headers = r.ReadSerializableArray <Block>() }); } }).OrderBy(p => p.Index).SelectMany(p => p.Headers).ToArray()) { if (header.Hash != GenesisBlock.Hash) { header_chain.Add(header.Hash, header, header.PrevBlock); header_index.Add(header.Hash); } stored_header_count++; } if (stored_header_count == 0) { Dictionary <UInt256, Block> table = db.Find(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block), (k, v) => Block.FromTrimmedData(v.ToArray(), sizeof(long))).ToDictionary(p => p.PrevBlock); for (UInt256 hash = GenesisBlock.Hash; hash != current_block_hash;) { Block header = table[hash]; header_chain.Add(header.Hash, header, header.PrevBlock); header_index.Add(header.Hash); hash = header.Hash; } } else if (current_block_height >= stored_header_count) { List <Block> list = new List <Block>(); for (UInt256 hash = current_block_hash; hash != header_index[(int)stored_header_count - 1];) { Block header = Block.FromTrimmedData(db.Get(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(hash)).ToArray(), sizeof(long)); list.Add(header); header_index.Insert((int)stored_header_count, hash); hash = header.PrevBlock; } for (int i = list.Count - 1; i >= 0; i--) { header_chain.Add(list[i].Hash, list[i], list[i].PrevBlock); } } this.current_header_hash = header_index[header_index.Count - 1]; } else { WriteBatch batch = new WriteBatch(); ReadOptions options = new ReadOptions { FillCache = false }; using (Iterator it = db.NewIterator(options)) { for (it.SeekToFirst(); it.Valid(); it.Next()) { batch.Delete(it.Key()); } } db.Write(WriteOptions.Default, batch); Persist(GenesisBlock); db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Version), Assembly.GetExecutingAssembly().GetName().Version.ToString()); } thread_persistence = new Thread(PersistBlocks); thread_persistence.Name = "LevelDBBlockchain.PersistBlocks"; thread_persistence.Start(); AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; }