예제 #1
0
 public LevelDBBlockchain()
 {
     Slice value;
     db = DB.Open(Settings.Default.DataDirectoryPath);
     if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Initialized), out value) && value.ToBoolean())
     {
         value = db.Get(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock));
         this.current_block = new UInt256(value.ToArray().Take(32).ToArray());
         this.current_height = BitConverter.ToUInt32(value.ToArray(), 32);
     }
     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());
             }
         }
         batch.Put(SliceBuilder.Begin(DataEntryPrefix.CFG_Version), 0);
         db.Write(WriteOptions.Default, batch);
         AddBlockToChain(GenesisBlock);
         db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.CFG_Initialized), true);
     }
     thread_persistence = new Thread(PersistBlocks);
     thread_persistence.Name = "LevelDBBlockchain.PersistBlocks";
     thread_persistence.Start();
     AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
 }
예제 #2
0
        public void PruneElements(IEnumerable<KeyValuePair<UInt256, IEnumerable<int>>> blockTxIndices)
        {
            using (var snapshot = db.GetSnapshot())
            {
                var readOptions = new ReadOptions { Snapshot = snapshot };
                using (var iterator = db.NewIterator(readOptions))
                {
                    foreach (var keyPair in blockTxIndices)
                    {
                        var blockHash = keyPair.Key;
                        var txIndices = keyPair.Value;

                        var pruningCursor = new LevelDbMerkleTreePruningCursor(blockHash, iterator);

                        // prune the transactions
                        foreach (var index in txIndices)
                        {
                            var cachedCursor = new CachedMerkleTreePruningCursor<BlockTxNode>(pruningCursor);
                            MerkleTree.PruneNode(cachedCursor, index);
                        }

                        var writeBatch = pruningCursor.CreateWriteBatch();
                        try
                        {
                            db.Write(new WriteOptions(), writeBatch);
                        }
                        finally
                        {
                            writeBatch.Dispose();
                        }
                    }
                }
            }
        }
예제 #3
0
 public override IEnumerable<RegisterTransaction> GetAssets()
 {
     yield return AntCoin;
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         foreach (Slice key in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_Asset), (k, v) => k))
         {
             UInt256 hash = new UInt256(key.ToArray().Skip(1).ToArray());
             yield return (RegisterTransaction)GetTransaction(hash, options);
         }
     }
 }
예제 #4
0
파일: DBTests.cs 프로젝트: vebin/BD2
        public void Snapshot()
        {
            // modify db
            Database.Put ("key1", "value1");

            // create snapshot
            var snapshot = Database.CreateSnapshot ();

            // modify db again
            Database.Put ("key2", "value2");

            // read from snapshot
            var readOptions = new ReadOptions () {
                Snapshot = snapshot
            };
            var val1 = Database.Get (readOptions, "key1");
            Assert.AreEqual ("value1", val1);
            var val2 = Database.Get (readOptions, "key2");
            Assert.IsNull (val2);

            // read from non-snapshot
            readOptions.Snapshot = null;
            val1 = Database.Get (readOptions, "key1");
            Assert.AreEqual ("value1", val1);
            val2 = Database.Get (readOptions, "key2");
            Assert.AreEqual ("value2", val2);

            // release snapshot
            // GC calls ~Snapshot() for us
        }
예제 #5
0
파일: DBTests.cs 프로젝트: vebin/BD2
        public void Get()
        {
            Database.Put (null, "key1", "value1");
            var value1 = Database.Get (null, "key1");
            Assert.AreEqual ("value1", value1);

            Database.Put (null, "key2", "value2");
            var value2 = Database.Get (null, "key2");
            Assert.AreEqual ("value2", value2);

            Database.Put (null, "key3", "value3");
            var value3 = Database.Get (null, "key3");
            Assert.AreEqual ("value3", value3);

            // verify checksum
            var options = new ReadOptions () {
                VerifyChecksums = true
            };
            value1 = Database.Get (options, "key1");
            Assert.AreEqual ("value1", value1);

            // no fill cache
            options = new ReadOptions () {
                FillCache = false
            };
            value2 = Database.Get (options, "key2");
            Assert.AreEqual ("value2", value2);
        }
예제 #6
0
        public ChainedHeader FindMaxTotalWork()
        {
            var maxTotalWork = BigInteger.Zero;
            var candidateHeaders = new List<ChainedHeader>();

            using (var snapshot = db.GetSnapshot())
            {
                var readOptions = new ReadOptions { Snapshot = snapshot };

                using (var iterator = db.NewIterator(readOptions))
                {
                    // totalWork will be sorted lowest to highest
                    iterator.SeekToLast();
                    while (iterator.Valid())
                    {
                        var key = iterator.Key().ToArray();
                        if (key[0] != TOTAL_WORK_PREFIX)
                            break;

                        UInt256 blockHash;
                        BigInteger totalWork;
                        DecodeTotalWorkKey(key, out blockHash, out totalWork);

                        // check if this block is valid
                        bool isValid;
                        var blockInvalidKey = MakeBlockInvalidKey(blockHash);
                        Slice blockInvalidSlice;
                        if (db.TryGet(readOptions, blockInvalidKey, out blockInvalidSlice))
                        {
                            var blockInvalidBytes = blockInvalidSlice.ToArray();
                            isValid = !(blockInvalidBytes.Length == 1 && blockInvalidBytes[0] == 1);
                        }
                        else
                            isValid = true;

                        if (isValid)
                        {
                            var headerKey = MakeHeaderKey(blockHash);
                            Slice headerSlice;
                            if (db.TryGet(readOptions, headerKey, out headerSlice))
                            {
                                // decode chained header
                                var chainedHeader = DataDecoder.DecodeChainedHeader(headerSlice.ToArray());

                                // initialize max total work, if it isn't yet
                                if (maxTotalWork == BigInteger.Zero)
                                    maxTotalWork = chainedHeader.TotalWork;

                                if (chainedHeader.TotalWork > maxTotalWork)
                                {
                                    maxTotalWork = chainedHeader.TotalWork;
                                    candidateHeaders = new List<ChainedHeader>();
                                }

                                // add this header as a candidate if it ties the max total work
                                if (chainedHeader.TotalWork >= maxTotalWork)
                                    candidateHeaders.Add(chainedHeader);
                                else
                                    break;
                            }
                        }

                        iterator.Prev();
                    }
                }
            }

            // take the earliest header seen with the max total work
            candidateHeaders.Sort((left, right) => left.DateSeen.CompareTo(right.DateSeen));
            return candidateHeaders.FirstOrDefault();
        }
예제 #7
0
 public override IEnumerable<Vote> GetVotes(IEnumerable<Transaction> others)
 {
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         foreach (var kv in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_Vote), (k, v) => new { Key = k, Value = v }))
         {
             UInt256 hash = new UInt256(kv.Key.ToArray().Skip(1).ToArray());
             ushort[] indexes = kv.Value.ToArray().GetUInt16Array().Except(others.SelectMany(p => p.GetAllInputs()).Where(p => p.PrevHash == hash).Select(p => p.PrevIndex)).ToArray();
             if (indexes.Length == 0) continue;
             VotingTransaction tx = (VotingTransaction)GetTransaction(hash, options);
             yield return new Vote
             {
                 Enrollments = tx.Enrollments,
                 Count = indexes.Sum(p => tx.Outputs[p].Value)
             };
         }
     }
     foreach (VotingTransaction tx in others.OfType<VotingTransaction>())
     {
         yield return new Vote
         {
             Enrollments = tx.Enrollments,
             Count = tx.Outputs.Where(p => p.AssetId == AntShare.Hash).Sum(p => p.Value)
         };
     }
 }
예제 #8
0
 public override IEnumerable<TransactionOutput> GetUnspentAntShares()
 {
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         foreach (var kv in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_AntShare), (k, v) => new { Key = k, Value = v }))
         {
             UInt256 hash = new UInt256(kv.Key.ToArray().Skip(1).ToArray());
             ushort[] indexes = kv.Value.ToArray().GetUInt16Array();
             Transaction tx = GetTransaction(hash, options);
             foreach (ushort index in indexes)
             {
                 yield return tx.Outputs[index];
             }
         }
     }
 }
예제 #9
0
 private Transaction GetTransaction(UInt256 hash, ReadOptions options)
 {
     Slice value;
     if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Transaction).Add(hash), out value))
         return null;
     return Transaction.DeserializeFrom(value.ToArray());
 }
예제 #10
0
        private IEnumerator<BlockTxNode> ReadBlockTransactions(UInt256 blockHash, bool requireTx)
        {
            using (var snapshot = db.GetSnapshot())
            {
                var readOptions = new ReadOptions { Snapshot = snapshot };
                using (var iterator = db.NewIterator(readOptions))
                {
                    iterator.Seek(DbEncoder.EncodeBlockHashTxIndex(blockHash, 0));
                    while (iterator.Valid())
                    {
                        var key = iterator.Key().ToArray();

                        UInt256 iteratorBlockHash; int txIndex;
                        DbEncoder.DecodeBlockHashTxIndex(key, out iteratorBlockHash, out txIndex);

                        if (iteratorBlockHash != blockHash)
                            yield break;

                        var value = iterator.Value().ToArray();

                        var blockTxNode = DataDecoder.DecodeBlockTxNode(value);

                        if (blockTxNode.Pruned && requireTx)
                            throw new MissingDataException(blockHash);

                        yield return blockTxNode;

                        iterator.Next();
                    }
                }
            }
        }
예제 #11
0
 private UInt256 GetNextBlockHash(UInt256 hash, ReadOptions options)
 {
     Slice value;
     if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.IX_PrevBlock).Add(hash), out value))
         return null;
     return new UInt256(value.ToArray());
 }
예제 #12
0
 private Block GetBlockAndHeight(UInt256 hash, ReadOptions options, out uint height)
 {
     Slice value;
     if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(hash), out value))
     {
         height = 0;
         return null;
     }
     byte[] data = value.ToArray();
     height = BitConverter.ToUInt32(data, 0);
     return Block.FromTrimmedData(data, sizeof(uint), p => GetTransaction(p, options));
 }
예제 #13
0
 public override Block GetNextBlock(UInt256 hash)
 {
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         hash = GetNextBlockHash(hash, options);
         uint height;
         return GetBlockAndHeight(hash, options, out height);
     }
 }
예제 #14
0
파일: DB.cs 프로젝트: vtchain/LevelDb.Net
 public Iterator NewIterator(ReadOptions options)
 {
     return(new Iterator(LevelDBInterop.leveldb_create_iterator(Handle, options.Handle)));
 }
예제 #15
0
        public IEnumerable<ChainedHeader> ReadChainedHeaders()
        {
            using (var snapshot = db.GetSnapshot())
            {
                var readOptions = new ReadOptions { Snapshot = snapshot };

                using (var iterator = db.NewIterator(readOptions))
                {
                    iterator.SeekToFirst();
                    while (iterator.Valid()
                        && iterator.Key().ToArray()[0] == HEADER_PREFIX)
                    {
                        var chainedHeader = DataDecoder.DecodeChainedHeader(iterator.Value().ToArray());
                        yield return chainedHeader;

                        iterator.Next();
                    }
                }
            }
        }
예제 #16
0
 private Block GetBlockInternal(UInt256 hash, ReadOptions options)
 {
     Slice value;
     if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(hash), out value))
         return null;
     return Block.FromTrimmedData(value.ToArray(), 0, p => GetTransaction(p, options));
 }
예제 #17
0
 public override IEnumerable<EnrollmentTransaction> GetEnrollments(IEnumerable<Transaction> others)
 {
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         foreach (Slice key in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_Enrollment), (k, v) => k))
         {
             UInt256 hash = new UInt256(key.ToArray().Skip(1).Take(32).ToArray());
             if (others.SelectMany(p => p.GetAllInputs()).Any(p => p.PrevHash == hash && p.PrevIndex == 0))
                 continue;
             yield return (EnrollmentTransaction)GetTransaction(hash, options);
         }
     }
     foreach (EnrollmentTransaction tx in others.OfType<EnrollmentTransaction>())
     {
         yield return tx;
     }
 }
예제 #18
0
        public bool TryAddBlockTransactions(UInt256 blockHash, IEnumerable<EncodedTx> blockTxes)
        {
            if (ContainsBlock(blockHash))
                return false;

            var writeBatch = new WriteBatch();
            try
            {
                int txCount;
                using (var snapshot = db.GetSnapshot())
                {
                    var readOptions = new ReadOptions { Snapshot = snapshot };

                    var txIndex = 0;
                    foreach (var tx in blockTxes)
                    {
                        var key = DbEncoder.EncodeBlockHashTxIndex(blockHash, txIndex);

                        Slice existingValue;
                        if (db.TryGet(readOptions, key, out existingValue))
                            return false;

                        var blockTx = new BlockTx(txIndex, tx);
                        var value = DataEncoder.EncodeBlockTxNode(blockTx);

                        writeBatch.Put(key, value);

                        txIndex++;
                    }

                    txCount = txIndex;
                }

                return TryAddBlockInner(blockHash, txCount, writeBatch);
            }
            finally
            {
                writeBatch.Dispose();
            }
        }
예제 #19
0
 public override TransactionOutput GetUnspent(UInt256 hash, ushort index)
 {
     TransactionOutput unspent = base.GetUnspent(hash, index);
     if (unspent != null) return unspent;
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         Slice value;
         if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.IX_Unspent).Add(hash), out value))
             return null;
         if (!value.ToArray().GetUInt16Array().Contains(index))
             return null;
         return GetTransaction(hash, options).Outputs[index];
     }
 }
예제 #20
0
        public bool TryRemoveBlockTransactions(UInt256 blockHash)
        {
            if (!ContainsBlock(blockHash))
                return false;

            var writeBatch = new WriteBatch();
            try
            {
                using (var snapshot = db.GetSnapshot())
                {
                    var readOptions = new ReadOptions { Snapshot = snapshot };
                    using (var iterator = db.NewIterator(readOptions))
                    {
                        iterator.Seek(DbEncoder.EncodeBlockHashTxIndex(blockHash, 0));
                        while (iterator.Valid())
                        {
                            var key = iterator.Key().ToArray();

                            UInt256 iteratorBlockHash; int txIndex;
                            DbEncoder.DecodeBlockHashTxIndex(key, out iteratorBlockHash, out txIndex);

                            if (iteratorBlockHash != blockHash)
                                break;

                            writeBatch.Delete(key);

                            iterator.Next();
                        }
                    }
                }

                return TryRemoveBlockInner(blockHash, writeBatch);
            }
            finally
            {
                writeBatch.Dispose();
            }
        }
예제 #21
0
 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.4"))
     {
         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(), 0)).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(), 0);
                 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;
 }
예제 #22
0
        /// <summary>
        /// If the database contains an entry for "key" return the value,
        /// otherwise return null.
        /// </summary>
        public string Get(string key, ReadOptions options)
        {
            var value = Get(Encoding.UTF8.GetBytes(key), options);

            return(value != null?Encoding.UTF8.GetString(value) : null);
        }
예제 #23
0
 public override bool IsDoubleSpend(Transaction tx)
 {
     TransactionInput[] inputs = tx.GetAllInputs().ToArray();
     if (inputs.Length == 0) return false;
     lock (MemoryPool)
     {
         if (MemoryPool.Values.SelectMany(p => p.GetAllInputs()).Intersect(inputs).Count() > 0)
             return true;
     }
     ReadOptions options = new ReadOptions();
     using (options.Snapshot = db.GetSnapshot())
     {
         foreach (var group in inputs.GroupBy(p => p.PrevHash))
         {
             Slice value;
             if (!db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.IX_Unspent).Add(group.Key), out value))
                 return true;
             HashSet<ushort> unspents = new HashSet<ushort>(value.ToArray().GetUInt16Array());
             if (group.Any(p => !unspents.Contains(p.PrevIndex)))
                 return true;
         }
     }
     return false;
 }
예제 #24
0
파일: DB.cs 프로젝트: robpaveza/leveldb.net
 /// <summary>
 /// Return an iterator over the contents of the database.
 /// The result of CreateIterator is initially invalid (caller must
 /// call one of the Seek methods on the iterator before using it).
 /// </summary>
 public Iterator CreateIterator(ReadOptions options)
 {
     return(new Iterator(LevelDBInterop.leveldb_create_iterator(this.Handle, options.Handle), _encoding));
 }