public void TestTransactionsWithCache()
        {
            string testFolder = TestUtils.PrepareTestFolder(GetType(), nameof(TestTransactionsWithCache), "*.db");

            using (SQLiteBlockchainStorage storage = SQLiteBlockchainStorage.Open(testFolder))
            {
                CachingBlockchainStorage cache = new CachingBlockchainStorage(storage);

                StoredBlockBuilder blockBuilder = new StoredBlockBuilder(GenesisBlock.GetHeader());
                blockBuilder.IsInBestHeaderChain = true;
                blockBuilder.IsInBestBlockChain = false;
                StoredBlock block = blockBuilder.Build();

                Assert.Throws<InvalidOperationException>(() => cache.AddBlock(block));

                using (new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.AddBlock(block);
                    Assert.That(cache.FindBlockByHash(block.Hash), Is.Not.Null);
                    Assert.That(cache.FindSubchain(block.Hash, 10), Is.Not.Null);
                }

                Assert.That(cache.FindBlockByHash(block.Hash), Is.Null);
                Assert.That(cache.FindSubchain(block.Hash, 10), Is.Null);

                using (var tx = new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.AddBlock(block);
                    tx.Complete();
                }

                Assert.That(cache.FindBlockByHash(block.Hash), Is.Not.Null);
                Assert.That(cache.FindSubchain(block.Hash, 10), Is.Not.Null);

                blockBuilder = new StoredBlockBuilder(block);
                blockBuilder.IsInBestBlockChain = true;
                block = blockBuilder.Build();

                Assert.Throws<InvalidOperationException>(() => cache.UpdateBlock(block));

                using (new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.UpdateBlock(block);
                    Assert.True(cache.FindBlockByHash(block.Hash).IsInBestBlockChain);
                    Assert.True(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).IsInBestBlockChain);
                }

                Assert.False(cache.FindBlockByHash(block.Hash).IsInBestBlockChain);
                Assert.False(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).IsInBestBlockChain);

                using (var tx = new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.UpdateBlock(block);
                    tx.Complete();
                }

                Assert.True(cache.FindBlockByHash(block.Hash).IsInBestBlockChain);
                Assert.True(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).IsInBestBlockChain);

                Assert.Throws<InvalidOperationException>(() => cache.AddBlockContent(block.Hash, GenesisBlock.Raw));

                using (new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.AddBlockContent(block.Hash, GenesisBlock.Raw);
                    Assert.True(cache.FindBlockByHash(block.Hash).HasContent);
                    Assert.True(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).HasContent);
                }

                Assert.False(cache.FindBlockByHash(block.Hash).HasContent);
                Assert.False(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).HasContent);

                using (var tx = new TransactionScope(TransactionScopeOption.Required))
                {
                    cache.AddBlockContent(block.Hash, GenesisBlock.Raw);
                    tx.Complete();
                }

                Assert.True(cache.FindBlockByHash(block.Hash).HasContent);
                Assert.True(cache.FindSubchain(block.Hash, 10).GetBlockByOffset(0).HasContent);
            }
        }
        public void TestTransactionsWithInternalBlockchain()
        {
            string testFolder = TestUtils.PrepareTestFolder(GetType(), nameof(TestTransactionsWithInternalBlockchain), "*.db");

            using (SQLiteBlockchainStorage storage = SQLiteBlockchainStorage.Open(testFolder))
            {
                CachingBlockchainStorage cache = new CachingBlockchainStorage(storage);
                InternalBlockchain blockchain = new InternalBlockchain(cache);

                using (var tx = new TransactionScope(TransactionScopeOption.Required))
                {
                    blockchain.Init();
                    tx.Complete();
                }

                using (new TransactionScope(TransactionScopeOption.Required))
                {
                    Assert.That(blockchain.CommitedState.BestHeader.Height, Is.EqualTo(0));
                    Assert.That(blockchain.CommitedState.BestChain.Height, Is.EqualTo(0));
                    blockchain.AddHeaders(new List<StoredBlock> {new StoredBlockBuilder(BitcoinStreamReader.FromBytes(KnownBlocks.Block1, BlockHeader.Read)).Build()});
                }

                using (var tx = new TransactionScope(TransactionScopeOption.Required))
                {
                    Assert.That(blockchain.CommitedState.BestHeader.Height, Is.EqualTo(0));
                    Assert.That(blockchain.CommitedState.BestChain.Height, Is.EqualTo(0));
                    blockchain.AddHeaders(new List<StoredBlock> {new StoredBlockBuilder(BitcoinStreamReader.FromBytes(KnownBlocks.Block1, BlockHeader.Read)).Build()});
                    tx.Complete();
                }

                using (new TransactionScope(TransactionScopeOption.Required))
                {
                    Assert.That(blockchain.CommitedState.BestHeader.Height, Is.EqualTo(1));
                    Assert.That(blockchain.CommitedState.BestChain.Height, Is.EqualTo(0));
                }
            }
        }
 public Blockchain(IBlockchainStorage storage)
 {
     CachingBlockchainStorage cache = new CachingBlockchainStorage(storage);
     blockchain = new InternalBlockchain(cache);
 }