// IBlockTxesStorage.TryGetTransaction
        private void TestTryGetTransaction(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // add block transactions
                blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                // verify missing transactions
                BlockTx transaction;
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(UInt256.Zero, 0, out transaction));
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(block.Hash, -1, out transaction));
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(block.Hash, block.Transactions.Length, out transaction));

                // verify transactions
                for (var txIndex = 0; txIndex < block.Transactions.Length; txIndex++)
                {
                    Assert.IsTrue(blockTxesStorage.TryGetTransaction(block.Hash, txIndex, out transaction));
                    Assert.AreEqual(block.Transactions[txIndex].Hash, transaction.Hash);
                    Assert.AreEqual(transaction.Hash, new UInt256(SHA256Static.ComputeDoubleHash(transaction.TxBytes.ToArray())));
                }
            }
        }
Beispiel #2
0
        // IBlockStorage.ContainsChainedHeader
        private void TestContainsChainedHeader(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create a chained header
                var fakeHeaders   = new FakeHeaders();
                var chainedHeader = fakeHeaders.GenesisChained();

                // header should not be present
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // add the header
                blockStorage.TryAddChainedHeader(chainedHeader);

                // header should be present
                Assert.IsTrue(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // remove the header
                blockStorage.TryRemoveChainedHeader(chainedHeader.Hash);

                // header should not be present
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash));
            }
        }
Beispiel #3
0
        // IBlockStorage.IsBlockInvalid
        // IBlockStorage.MarkBlockInvalid
        private void TestMarkBlockInvalid(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create chained headers
                var fakeHeaders    = new FakeHeaders();
                var chainedHeader0 = fakeHeaders.GenesisChained();
                var chainedHeader1 = fakeHeaders.NextChained();

                // add headers
                blockStorage.TryAddChainedHeader(chainedHeader0);
                blockStorage.TryAddChainedHeader(chainedHeader1);

                // verify no blocks invalid
                Assert.IsFalse(blockStorage.IsBlockInvalid(chainedHeader0.Hash));
                Assert.IsFalse(blockStorage.IsBlockInvalid(chainedHeader1.Hash));

                // mark blocks invalid and verify

                // 0
                blockStorage.MarkBlockInvalid(chainedHeader0.Hash);
                Assert.IsTrue(blockStorage.IsBlockInvalid(chainedHeader0.Hash));
                Assert.IsFalse(blockStorage.IsBlockInvalid(chainedHeader1.Hash));

                // 1
                blockStorage.MarkBlockInvalid(chainedHeader1.Hash);
                Assert.IsTrue(blockStorage.IsBlockInvalid(chainedHeader0.Hash));
                Assert.IsTrue(blockStorage.IsBlockInvalid(chainedHeader1.Hash));
            }
        }
        // IBlockTxesStorage.ReadBlockTransactions
        private void TestReadBlockTransactions(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var expectedBlock         = CreateFakeBlock();
                var expectedBlockTxHashes = expectedBlock.Transactions.Select(x => x.Hash).ToList();

                // add block transactions
                blockTxesStorage.TryAddBlockTransactions(expectedBlock.Hash, expectedBlock.BlockTxes);

                // retrieve block transactions
                IEnumerator <BlockTx> rawActualBlockTxes;
                Assert.IsTrue(blockTxesStorage.TryReadBlockTransactions(expectedBlock.Hash, out rawActualBlockTxes));
                var actualBlockTxes     = rawActualBlockTxes.UsingAsEnumerable().ToList();
                var actualBlockTxHashes = actualBlockTxes.Select(x => x.Hash).ToList();

                // verify all retrieved transactions match their hashes
                Assert.IsTrue(actualBlockTxes.All(x => x.Hash == new UInt256(SHA256Static.ComputeDoubleHash(x.TxBytes.ToArray()))));

                // verify retrieved block transactions match stored block transactions
                CollectionAssert.AreEqual(expectedBlockTxHashes, actualBlockTxHashes);
            }
        }
        // IBlockTxesStorage.ContainsBlock
        private void TestContainsBlock(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // block should not be present
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));

                // add the block
                blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                // block should be present
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // remove the block
                blockTxesStorage.TryRemoveBlockTransactions(block.Hash);

                // block should not be present
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));
            }
        }
Beispiel #6
0
        private void TestInTransaction(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // verify initial InTransaction=false
                    Assert.IsFalse(chainStateCursor.InTransaction);

                    // begin transaction and verify InTransaction=true
                    chainStateCursor.BeginTransaction();
                    Assert.IsTrue(chainStateCursor.InTransaction);

                    // rollback transaction and verify InTransaction=false
                    chainStateCursor.RollbackTransaction();
                    Assert.IsFalse(chainStateCursor.InTransaction);

                    // begin transaction and verify InTransaction=true
                    chainStateCursor.BeginTransaction();
                    Assert.IsTrue(chainStateCursor.InTransaction);

                    // commit transaction and verify InTransaction=false
                    chainStateCursor.CommitTransaction();
                    Assert.IsFalse(chainStateCursor.InTransaction);
                }
        }
Beispiel #7
0
        // IBlockStorage.TryAddChainedHeader
        // IBlockStorage.TryRemoveChainedHeader
        private void TestTryAddRemoveChainedHeader(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create a chained header
                var fakeHeaders   = new FakeHeaders();
                var chainedHeader = fakeHeaders.GenesisChained();

                // verify header can be added
                Assert.IsTrue(blockStorage.TryAddChainedHeader(chainedHeader));
                Assert.IsTrue(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // verify header cannot be added again
                Assert.IsFalse(blockStorage.TryAddChainedHeader(chainedHeader));

                // remove the header
                Assert.IsTrue(blockStorage.TryRemoveChainedHeader(chainedHeader.Hash));
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // verify header cannot be removed again
                Assert.IsFalse(blockStorage.TryRemoveChainedHeader(chainedHeader.Hash));

                // verify header can be added again, after being removed
                Assert.IsTrue(blockStorage.TryAddChainedHeader(chainedHeader));
                Assert.IsTrue(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // verify header can be removed again, after being added again
                Assert.IsTrue(blockStorage.TryRemoveChainedHeader(chainedHeader.Hash));
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash));
            }
        }
        // IBlockTxesStorage.TryAddRemoveBlockTransactions
        // IBlockTxesStorage.TryRemoveRemoveBlockTransactions
        private void TestTryAddRemoveBlockTransactions(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // verify block can be added
                Assert.IsTrue(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block cannot be added again
                Assert.IsFalse(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));

                // remove the block
                Assert.IsTrue(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block cannot be removed again
                Assert.IsFalse(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));

                // verify block can be added again, after being removed
                Assert.IsTrue(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block can be removed again, after being added again
                Assert.IsTrue(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));
            }
        }
        // IBlockStorage.ContainsChainedHeader
        private void TestContainsChainedHeader(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create a chained header
                var fakeHeaders = new FakeHeaders();
                var chainedHeader = fakeHeaders.GenesisChained();

                // header should not be present
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash));

                // add the header
                blockStorage.TryAddChainedHeader(chainedHeader);

                // header should be present
                Assert.IsTrue(blockStorage.ContainsChainedHeader(chainedHeader.Hash)); ;

                // remove the header
                blockStorage.TryRemoveChainedHeader(chainedHeader.Hash);

                // header should not be present
                Assert.IsFalse(blockStorage.ContainsChainedHeader(chainedHeader.Hash)); ;
            }
        }
Beispiel #10
0
        // IBlockStorage.Defragment
        private void TestDefragment(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                Assert.Inconclusive("TODO");
            }
        }
Beispiel #11
0
        public void TestTryAddGetRemoveBlockSpentTxes(ITestStorageProvider provider)
        {
            var spentTxes0 = ImmutableList.Create(
                new SpentTx(txHash: 0, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0),
                new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 1, outputCount: 2, spentBlockIndex: 0),
                new SpentTx(txHash: 2, confirmedBlockIndex: 0, txIndex: 2, outputCount: 3, spentBlockIndex: 0));

            var spentTxes1 = ImmutableList.Create(
                new SpentTx(txHash: 100, confirmedBlockIndex: 1, txIndex: 0, outputCount: 1, spentBlockIndex: 1),
                new SpentTx(txHash: 101, confirmedBlockIndex: 1, txIndex: 1, outputCount: 2, spentBlockIndex: 1));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial empty state
                    IImmutableList <SpentTx> actualSpentTxes0, actualSpentTxes1;
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                    // add spent txes 0
                    Assert.IsTrue(chainStateCursor.TryAddBlockSpentTxes(0, spentTxes0));

                    // verify spent txes
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                    CollectionAssert.AreEqual(spentTxes0, (ICollection)actualSpentTxes0);
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                    // add spent txes 1
                    Assert.IsTrue(chainStateCursor.TryAddBlockSpentTxes(1, spentTxes1));

                    // verify spent txes
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                    CollectionAssert.AreEqual(spentTxes0, (ICollection)actualSpentTxes0);
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));
                    CollectionAssert.AreEqual(spentTxes1, (ICollection)actualSpentTxes1);

                    // remove spent txes 1
                    Assert.IsTrue(chainStateCursor.TryRemoveBlockSpentTxes(1));

                    // verify spent txes
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                    CollectionAssert.AreEqual(spentTxes0, (ICollection)actualSpentTxes0);
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                    // remove spent txes 0
                    Assert.IsTrue(chainStateCursor.TryRemoveBlockSpentTxes(0));

                    // verify spent txes
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));
                }
        }
Beispiel #12
0
        private void TestGetChainTip(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();
            var chainedHeader2 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial empty chain
                    Assert.IsNull(chainStateCursor.GetChainTip());

                    // add header 0
                    chainStateCursor.AddChainedHeader(chainedHeader0);

                    // verify chain tip
                    Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip());

                    // add header 1
                    chainStateCursor.AddChainedHeader(chainedHeader1);

                    // verify chain tip
                    Assert.AreEqual(chainedHeader1, chainStateCursor.GetChainTip());

                    // add header 2
                    chainStateCursor.AddChainedHeader(chainedHeader2);

                    // verify chain tip
                    Assert.AreEqual(chainedHeader2, chainStateCursor.GetChainTip());

                    // remove header 2
                    chainStateCursor.RemoveChainedHeader(chainedHeader2);

                    // verify chain tip
                    Assert.AreEqual(chainedHeader1, chainStateCursor.GetChainTip());

                    // remove header 1
                    chainStateCursor.RemoveChainedHeader(chainedHeader1);

                    // verify chain tip
                    Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip());

                    // remove header 0
                    chainStateCursor.RemoveChainedHeader(chainedHeader0);

                    // verify chain tip
                    Assert.IsNull(chainStateCursor.GetChainTip());
                }
        }
Beispiel #13
0
        private void TestReadChain(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();
            var chainedHeader2 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial empty chain
                    Assert.AreEqual(0, chainStateCursor.ReadChain().Count());

                    // add header 0
                    chainStateCursor.AddChainedHeader(chainedHeader0);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList());

                    // add header 1
                    chainStateCursor.AddChainedHeader(chainedHeader1);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0, chainedHeader1 }, chainStateCursor.ReadChain().ToList());

                    // add header 2
                    chainStateCursor.AddChainedHeader(chainedHeader2);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0, chainedHeader1, chainedHeader2 }, chainStateCursor.ReadChain().ToList());

                    // remove header 2
                    chainStateCursor.RemoveChainedHeader(chainedHeader2);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0, chainedHeader1 }, chainStateCursor.ReadChain().ToList());

                    // remove header 1
                    chainStateCursor.RemoveChainedHeader(chainedHeader1);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList());

                    // remove header 0
                    chainStateCursor.RemoveChainedHeader(chainedHeader0);

                    // verify chain
                    Assert.AreEqual(0, chainStateCursor.ReadChain().Count());
                }
        }
Beispiel #14
0
        private void TestRollbackTransaction(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();
            var chainedHeader2 = fakeHeaders.NextChained();

            var unspentTx = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            var spentTxes = ImmutableList.Create(new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // add header 0
                    chainStateCursor.AddChainedHeader(chainedHeader0);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList());

                    // add unspent tx
                    chainStateCursor.TryAddUnspentTx(unspentTx);

                    // verify unspent tx
                    Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash));
                    Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                    // add spent txes
                    chainStateCursor.TryAddBlockSpentTxes(0, spentTxes);

                    // verify spent txes
                    IImmutableList <SpentTx> actualSpentTxes;
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                    CollectionAssert.AreEqual(spentTxes, (ICollection)actualSpentTxes);

                    // rollback transaction
                    chainStateCursor.RollbackTransaction();

                    // verify chain
                    Assert.AreEqual(0, chainStateCursor.ReadChain().Count());

                    // verify unspent tx
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash));
                    Assert.AreEqual(0, chainStateCursor.UnspentTxCount);

                    // verify spent txes
                    Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                }
        }
Beispiel #15
0
        private void TestUnspentTxCount(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx2 = new UnspentTx(txHash: 2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial count
                    Assert.AreEqual(0, chainStateCursor.UnspentTxCount);

                    // add unspent tx 0
                    chainStateCursor.TryAddUnspentTx(unspentTx0);

                    // verify count
                    Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                    // add unspent tx 1
                    chainStateCursor.TryAddUnspentTx(unspentTx1);

                    // verify count
                    Assert.AreEqual(2, chainStateCursor.UnspentTxCount);

                    // add unspent tx 2
                    chainStateCursor.TryAddUnspentTx(unspentTx2);

                    // verify count
                    Assert.AreEqual(3, chainStateCursor.UnspentTxCount);

                    // remove unspent tx 2
                    chainStateCursor.TryRemoveUnspentTx(unspentTx2.TxHash);

                    // verify count
                    Assert.AreEqual(2, chainStateCursor.UnspentTxCount);

                    // remove unspent tx 1
                    chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash);

                    // verify count
                    Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                    // remove unspent tx 0
                    chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash);

                    // verify count
                    Assert.AreEqual(0, chainStateCursor.UnspentTxCount);
                }
        }
Beispiel #16
0
        public void TestReadUnspentTransactions(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx2 = new UnspentTx(txHash: 2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial empty state
                    Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count());

                    // add unspent tx 0
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx0));

                    // verify unspent txes
                    CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList());

                    // add unspent tx 1
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx1));

                    // verify unspent txes
                    CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList());

                    // add unspent tx 2
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx2));

                    // verify unspent txes
                    CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1, unspentTx2 }, chainStateCursor.ReadUnspentTransactions().ToList());

                    // remove unspent tx 2
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx2.TxHash));

                    // verify unspent txes
                    CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList());

                    // remove unspent tx 1
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash));

                    // verify unspent txes
                    CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList());

                    // remove unspent tx 0
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash));

                    // verify unspent txes
                    Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count());
                }
        }
Beispiel #17
0
        public void TestContainsBlockSpentTxes(ITestStorageProvider provider)
        {
            var spentTxes0 = ImmutableList.Create(
                new SpentTx(txHash: 0, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0),
                new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 1, outputCount: 2, spentBlockIndex: 0),
                new SpentTx(txHash: 2, confirmedBlockIndex: 0, txIndex: 2, outputCount: 3, spentBlockIndex: 0));

            var spentTxes1 = ImmutableList.Create(
                new SpentTx(txHash: 100, confirmedBlockIndex: 1, txIndex: 0, outputCount: 1, spentBlockIndex: 1),
                new SpentTx(txHash: 101, confirmedBlockIndex: 1, txIndex: 1, outputCount: 2, spentBlockIndex: 1));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify presence
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(0));
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                    // add spent txes 0
                    chainStateCursor.TryAddBlockSpentTxes(0, spentTxes0);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                    // add unspent tx 1
                    chainStateCursor.TryAddBlockSpentTxes(1, spentTxes1);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                    Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(1));

                    // remove unspent tx 1
                    chainStateCursor.TryRemoveBlockSpentTxes(1);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                    // remove unspent tx 0
                    chainStateCursor.TryRemoveBlockSpentTxes(0);

                    // verify presence
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(0));
                    Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));
                }
        }
Beispiel #18
0
        private void TestTryAddGetRemoveUnspentTx(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify initial empty state
                    UnspentTx actualUnspentTx0, actualUnspentTx1;
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0));
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1));

                    // add unspent tx 0
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx0));

                    // verify unspent txes
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0));
                    Assert.AreEqual(unspentTx0, actualUnspentTx0);
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1));

                    // add unspent tx 1
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx1));

                    // verify unspent txes
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0));
                    Assert.AreEqual(unspentTx0, actualUnspentTx0);
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1));
                    Assert.AreEqual(unspentTx1, actualUnspentTx1);

                    // remove unspent tx 1
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash));

                    // verify unspent txes
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0));
                    Assert.AreEqual(unspentTx0, actualUnspentTx0);
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1));

                    // remove unspent tx 0
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash));

                    // verify unspent txes
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx0.TxHash, out actualUnspentTx0));
                    Assert.IsFalse(chainStateCursor.TryGetUnspentTx(unspentTx1.TxHash, out actualUnspentTx1));
                }
        }
Beispiel #19
0
        private void TestCommitTransaction(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var unspentTx      = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var spentTxes      = ImmutableList.Create(new SpentTx(txHash: 1, confirmedBlockIndex: 0, txIndex: 0, outputCount: 1, spentBlockIndex: 0));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // add data
                    chainStateCursor.AddChainedHeader(chainedHeader0);
                    chainStateCursor.TryAddUnspentTx(unspentTx);
                    chainStateCursor.TryAddBlockSpentTxes(0, spentTxes);

                    // verify data
                    Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip());
                    Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                    UnspentTx actualUnspentTx;
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                    Assert.AreEqual(unspentTx, actualUnspentTx);

                    IImmutableList <SpentTx> actualSpentTxes;
                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                    CollectionAssert.AreEqual((ICollection)spentTxes, (ICollection)actualSpentTxes);

                    // commit transaction
                    chainStateCursor.CommitTransaction();

                    // verify data
                    Assert.AreEqual(chainedHeader0, chainStateCursor.GetChainTip());
                    Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                    Assert.AreEqual(unspentTx, actualUnspentTx);

                    Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                    CollectionAssert.AreEqual((ICollection)spentTxes, (ICollection)actualSpentTxes);
                }
        }
Beispiel #20
0
        private void TestContainsUnspentTx(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: 1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify presence
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                    // add unspent tx 0
                    chainStateCursor.TryAddUnspentTx(unspentTx0);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                    // add unspent tx 1
                    chainStateCursor.TryAddUnspentTx(unspentTx1);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                    Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                    // remove unspent tx 1
                    chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash);

                    // verify presence
                    Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                    // remove unspent tx 0
                    chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash);

                    // verify presence
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                    Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));
                }
        }
Beispiel #21
0
        // IBlockStorage.FindMaxTotalWork
        private void TestFindMaxTotalWork(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create chained headers
                var fakeHeaders    = new FakeHeaders();
                var chainedHeader0 = fakeHeaders.GenesisChained();
                var chainedHeader1 = fakeHeaders.NextChained();
                var chainedHeader2 = fakeHeaders.NextChained();

                // verify initial null state
                Assert.IsNull(blockStorage.FindMaxTotalWork());

                // add headers and verify max total work

                // 0
                blockStorage.TryAddChainedHeader(chainedHeader0);
                Assert.AreEqual(chainedHeader0, blockStorage.FindMaxTotalWork());

                // 1
                blockStorage.TryAddChainedHeader(chainedHeader1);
                Assert.AreEqual(chainedHeader1, blockStorage.FindMaxTotalWork());

                // 2
                blockStorage.TryAddChainedHeader(chainedHeader2);
                Assert.AreEqual(chainedHeader2, blockStorage.FindMaxTotalWork());

                // remove headers and verify max total work

                // 2
                blockStorage.TryRemoveChainedHeader(chainedHeader2.Hash);
                Assert.AreEqual(chainedHeader1, blockStorage.FindMaxTotalWork());

                // 1
                blockStorage.TryRemoveChainedHeader(chainedHeader1.Hash);
                Assert.AreEqual(chainedHeader0, blockStorage.FindMaxTotalWork());

                // 0
                blockStorage.TryRemoveChainedHeader(chainedHeader0.Hash);
                Assert.IsNull(blockStorage.FindMaxTotalWork());
            }
        }
Beispiel #22
0
        // IBlockStorage.ReadChainedHeaders
        private void TestReadChainedHeaders(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create chained headers
                var fakeHeaders    = new FakeHeaders();
                var chainedHeader0 = fakeHeaders.GenesisChained();
                var chainedHeader1 = fakeHeaders.NextChained();
                var chainedHeader2 = fakeHeaders.NextChained();

                // verify initial empty state
                Assert.AreEqual(0, blockStorage.ReadChainedHeaders().ToList().Count);

                // add headers and verify reading them

                // 0
                blockStorage.TryAddChainedHeader(chainedHeader0);
                CollectionAssert.AreEquivalent(new[] { chainedHeader0 }, blockStorage.ReadChainedHeaders().ToList());

                // 1
                blockStorage.TryAddChainedHeader(chainedHeader1);
                CollectionAssert.AreEquivalent(new[] { chainedHeader0, chainedHeader1 }, blockStorage.ReadChainedHeaders().ToList());

                // 2
                blockStorage.TryAddChainedHeader(chainedHeader2);
                CollectionAssert.AreEquivalent(new[] { chainedHeader0, chainedHeader1, chainedHeader2 }, blockStorage.ReadChainedHeaders().ToList());

                // remove headers and verify reading them

                // 2
                blockStorage.TryRemoveChainedHeader(chainedHeader2.Hash);
                CollectionAssert.AreEquivalent(new[] { chainedHeader0, chainedHeader1 }, blockStorage.ReadChainedHeaders().ToList());

                // 1
                blockStorage.TryRemoveChainedHeader(chainedHeader1.Hash);
                CollectionAssert.AreEquivalent(new[] { chainedHeader0 }, blockStorage.ReadChainedHeaders().ToList());

                // 0
                blockStorage.TryRemoveChainedHeader(chainedHeader0.Hash);
                Assert.AreEqual(0, blockStorage.ReadChainedHeaders().ToList().Count);
            }
        }
        // IBlockTxesStorage.BlockCount
        private void TestBlockCount(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create blocks
                var fakeBlock0 = CreateFakeBlock();
                var fakeBlock1 = CreateFakeBlock();
                var fakeBlock2 = CreateFakeBlock();

                // verify initial count of 0
                Assert.AreEqual(0, blockTxesStorage.BlockCount);

                // add blocks and verify count

                // 0
                blockTxesStorage.TryAddBlockTransactions(fakeBlock0.Hash, fakeBlock0.BlockTxes);
                Assert.AreEqual(1, blockTxesStorage.BlockCount);

                // 1
                blockTxesStorage.TryAddBlockTransactions(fakeBlock1.Hash, fakeBlock1.BlockTxes);
                Assert.AreEqual(2, blockTxesStorage.BlockCount);

                // 2
                blockTxesStorage.TryAddBlockTransactions(fakeBlock2.Hash, fakeBlock2.BlockTxes);
                Assert.AreEqual(3, blockTxesStorage.BlockCount);

                // remove blocks and verify count

                // 0
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock0.Hash);
                Assert.AreEqual(2, blockTxesStorage.BlockCount);

                // 1
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock1.Hash);
                Assert.AreEqual(1, blockTxesStorage.BlockCount);

                // 2
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock2.Hash);
                Assert.AreEqual(0, blockTxesStorage.BlockCount);
            }
        }
        // IBlockTxesStorage.BlockCount
        private void TestBlockCount(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create blocks
                var fakeBlock0 = CreateFakeBlock();
                var fakeBlock1 = CreateFakeBlock();
                var fakeBlock2 = CreateFakeBlock();

                // verify initial count of 0
                Assert.AreEqual(0, blockTxesStorage.BlockCount);

                // add blocks and verify count

                // 0
                blockTxesStorage.TryAddBlockTransactions(fakeBlock0.Hash, fakeBlock0.BlockTxes);
                Assert.AreEqual(1, blockTxesStorage.BlockCount);

                // 1
                blockTxesStorage.TryAddBlockTransactions(fakeBlock1.Hash, fakeBlock1.BlockTxes);
                Assert.AreEqual(2, blockTxesStorage.BlockCount);

                // 2
                blockTxesStorage.TryAddBlockTransactions(fakeBlock2.Hash, fakeBlock2.BlockTxes);
                Assert.AreEqual(3, blockTxesStorage.BlockCount);

                // remove blocks and verify count

                // 0
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock0.Hash);
                Assert.AreEqual(2, blockTxesStorage.BlockCount);

                // 1
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock1.Hash);
                Assert.AreEqual(1, blockTxesStorage.BlockCount);

                // 2
                blockTxesStorage.TryRemoveBlockTransactions(fakeBlock2.Hash);
                Assert.AreEqual(0, blockTxesStorage.BlockCount);
            }
        }
Beispiel #25
0
        private void TestTransactionIsolation(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();

            // open two chain state cursors
            using (var storageManager = provider.OpenStorageManager())
                using (var handle1 = storageManager.OpenChainStateCursor())
                    using (var handle2 = storageManager.OpenChainStateCursor())
                    {
                        var chainStateCursor1 = handle1.Item;
                        var chainStateCursor2 = handle2.Item;

                        // open transactions on both cursors
                        chainStateCursor1.BeginTransaction();
                        chainStateCursor2.BeginTransaction();

                        // verify initial empty chain
                        Assert.AreEqual(0, chainStateCursor1.ReadChain().Count());
                        Assert.AreEqual(0, chainStateCursor2.ReadChain().Count());

                        // add a header on cursor 1
                        chainStateCursor1.AddChainedHeader(chainedHeader0);

                        // verify cursor 1 sees the new header while cursor 2 does not
                        CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor1.ReadChain().ToList());
                        Assert.AreEqual(0, chainStateCursor2.ReadChain().Count());

                        // commit cursor 1
                        chainStateCursor1.CommitTransaction();

                        // verify cursor 1 sees the new header while cursor 2 does not
                        CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor1.ReadChain().ToList());
                        Assert.AreEqual(0, chainStateCursor2.ReadChain().Count());

                        // commit cursor 2
                        chainStateCursor2.CommitTransaction();

                        // verify cursor 2 now sees the new header
                        CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor2.ReadChain().ToList());
                    }
        }
Beispiel #26
0
        // IBlockStorage.TryGetChainedHeader
        private void TestTryGetChainedHeader(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockStorage = storageManager.BlockStorage;

                // create a chained header
                var fakeHeaders           = new FakeHeaders();
                var expectedChainedHeader = fakeHeaders.GenesisChained();

                // add header
                blockStorage.TryAddChainedHeader(expectedChainedHeader);

                // retrieve header
                ChainedHeader actualChainedHeader;
                Assert.IsTrue(blockStorage.TryGetChainedHeader(expectedChainedHeader.Hash, out actualChainedHeader));

                // verify retrieved header matches stored header
                Assert.AreEqual(expectedChainedHeader, actualChainedHeader);
            }
        }
Beispiel #27
0
        private void TestRemoveChainedHeader(ITestStorageProvider provider)
        {
            var fakeHeaders    = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // add headers
                    chainStateCursor.AddChainedHeader(chainedHeader0);
                    chainStateCursor.AddChainedHeader(chainedHeader1);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0, chainedHeader1 }, chainStateCursor.ReadChain().ToList());

                    // remove header 1
                    chainStateCursor.RemoveChainedHeader(chainedHeader1);

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList());

                    // try to remove header 1 again
                    AssertThrows <InvalidOperationException>(() => chainStateCursor.RemoveChainedHeader(chainedHeader1));

                    // verify chain
                    CollectionAssert.AreEqual(new[] { chainedHeader0 }, chainStateCursor.ReadChain().ToList());

                    // remove header 0
                    chainStateCursor.RemoveChainedHeader(chainedHeader0);

                    // verify chain
                    Assert.AreEqual(0, chainStateCursor.ReadChain().Count());
                }
        }
Beispiel #28
0
        private void TestTryUpdateUnspentTx(ITestStorageProvider provider)
        {
            var unspentTx        = new UnspentTx(txHash: 0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTxUpdated = unspentTx.SetOutputState(0, OutputState.Spent);

            Assert.AreNotEqual(unspentTx, unspentTxUpdated);

            using (var storageManager = provider.OpenStorageManager())
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor = handle.Item;

                    // begin transaction
                    chainStateCursor.BeginTransaction();

                    // verify can't update missing unspent tx
                    Assert.IsFalse(chainStateCursor.TryUpdateUnspentTx(unspentTx));

                    // add unspent tx
                    Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx));

                    // verify unspent tx
                    UnspentTx actualUnspentTx;
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                    Assert.AreEqual(unspentTx, actualUnspentTx);

                    // update unspent tx
                    Assert.IsTrue(chainStateCursor.TryUpdateUnspentTx(unspentTxUpdated));

                    // verify updated unspent tx
                    Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                    Assert.AreEqual(unspentTxUpdated, actualUnspentTx);

                    // remove unspent tx
                    Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx.TxHash));

                    // verify can't update missing unspent tx
                    Assert.IsFalse(chainStateCursor.TryUpdateUnspentTx(unspentTx));
                }
        }
Beispiel #29
0
        private void TestRollbackOfFailedChainStateCursor(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                // begin a transaction on a cursor and return it without committing or rolling back
                IChainStateCursor chainStateCursor;
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    chainStateCursor = handle.Item;
                    chainStateCursor.BeginTransaction();
                }

                using (var handle = storageManager.OpenChainStateCursor())
                {
                    // verify the same cursor was retrieved, ignore storage providers that do not re-use cursors
                    Assert.AreSame(handle.Item, chainStateCursor);

                    // verify the cursor is no longer in a transaction
                    chainStateCursor = handle.Item;
                    Assert.IsFalse(chainStateCursor.InTransaction);
                }
            }
        }
        private void TestRollbackOfFailedChainStateCursor(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                // begin a transaction on a cursor and return it without committing or rolling back
                IChainStateCursor chainStateCursor;
                using (var handle = storageManager.OpenChainStateCursor())
                {
                    chainStateCursor = handle.Item;
                    chainStateCursor.BeginTransaction();
                }

                using (var handle = storageManager.OpenChainStateCursor())
                {
                    // verify the same cursor was retrieved, ignore storage providers that do not re-use cursors
                    Assert.AreSame(handle.Item, chainStateCursor);

                    // verify the cursor is no longer in a transaction
                    chainStateCursor = handle.Item;
                    Assert.IsFalse(chainStateCursor.InTransaction);
                }
            }
        }
        // IBlockTxesStorage.ReadBlockTransactions
        private void TestReadBlockTransactions(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var expectedBlock = CreateFakeBlock();
                var expectedBlockTxHashes = expectedBlock.Transactions.Select(x => x.Hash).ToList();

                // add block transactions
                blockTxesStorage.TryAddBlockTransactions(expectedBlock.Hash, expectedBlock.BlockTxes);

                // retrieve block transactions
                IEnumerator<BlockTx> rawActualBlockTxes;
                Assert.IsTrue(blockTxesStorage.TryReadBlockTransactions(expectedBlock.Hash, out rawActualBlockTxes));
                var actualBlockTxes = rawActualBlockTxes.UsingAsEnumerable().ToList();
                var actualBlockTxHashes = actualBlockTxes.Select(x => x.Hash).ToList();

                // verify all retrieved transactions match their hashes
                Assert.IsTrue(actualBlockTxes.All(x => x.Hash == new UInt256(SHA256Static.ComputeDoubleHash(x.TxBytes.ToArray()))));

                // verify retrieved block transactions match stored block transactions
                CollectionAssert.AreEqual(expectedBlockTxHashes, actualBlockTxHashes);
            }
        }
        // IBlockTxesStorage.TryAddRemoveBlockTransactions
        // IBlockTxesStorage.TryRemoveRemoveBlockTransactions
        private void TestTryAddRemoveBlockTransactions(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // verify block can be added
                Assert.IsTrue(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block cannot be added again
                Assert.IsFalse(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));

                // remove the block
                Assert.IsTrue(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block cannot be removed again
                Assert.IsFalse(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));

                // verify block can be added again, after being removed
                Assert.IsTrue(blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes));
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // verify block can be removed again, after being added again
                Assert.IsTrue(blockTxesStorage.TryRemoveBlockTransactions(block.Hash));
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));
            }
        }
        private void TestTryAddGetRemoveHeader(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var header0 = fakeHeaders.GenesisChained();
            var header1 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial empty state
                ChainedHeader actualHeader0, actualHeader1;
                Assert.IsFalse(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader0));
                Assert.IsFalse(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader1));

                // add header 0
                Assert.IsTrue(chainStateCursor.TryAddHeader(header0));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader0));
                Assert.AreEqual(header0, actualHeader0);
                Assert.IsFalse(chainStateCursor.TryGetHeader(header1.Hash, out actualHeader1));

                // add header 1
                Assert.IsTrue(chainStateCursor.TryAddHeader(header1));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader0));
                Assert.AreEqual(header0, actualHeader0);
                Assert.IsTrue(chainStateCursor.TryGetHeader(header1.Hash, out actualHeader1));
                Assert.AreEqual(header1, actualHeader1);

                // remove header 1
                Assert.IsTrue(chainStateCursor.TryRemoveHeader(header1.Hash));

                // verify unspent txes
                Assert.IsTrue(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader0));
                Assert.AreEqual(header0, actualHeader0);
                Assert.IsFalse(chainStateCursor.TryGetHeader(header1.Hash, out actualHeader1));

                // remove header 0
                Assert.IsTrue(chainStateCursor.TryRemoveHeader(header0.Hash));

                // verify unspent txes
                Assert.IsFalse(chainStateCursor.TryGetHeader(header0.Hash, out actualHeader0));
                Assert.IsFalse(chainStateCursor.TryGetHeader(header1.Hash, out actualHeader1));
            }
        }
        private void TestRollbackTransaction(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();
            var chainedHeader2 = fakeHeaders.NextChained();

            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Spent));
            var spentTxes = BlockSpentTxes.CreateRange(new[] { unspentTx.ToSpentTx() });

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // add header 0
                chainStateCursor.ChainTip = chainedHeader0;

                // verify chain
                Assert.AreEqual(chainedHeader0, chainStateCursor.ChainTip);

                // add unspent tx
                chainStateCursor.TryAddUnspentTx(unspentTx);
                chainStateCursor.UnspentTxCount++;

                // verify unspent tx
                Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash));
                Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                // add spent txes
                chainStateCursor.TryAddBlockSpentTxes(0, spentTxes);

                // verify spent txes
                BlockSpentTxes actualSpentTxes;
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                CollectionAssert.AreEqual(spentTxes.ToList(), actualSpentTxes.ToList());

                // rollback transaction
                chainStateCursor.RollbackTransaction();

                chainStateCursor.BeginTransaction();

                // verify chain
                Assert.IsNull(chainStateCursor.ChainTip);

                // verify unspent tx
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx.TxHash));
                Assert.AreEqual(0, chainStateCursor.UnspentTxCount);

                // verify spent txes
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));

                chainStateCursor.RollbackTransaction();
            }
        }
        private void TestContainsUnspentTx(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: (UInt256)0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: (UInt256)1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                // add unspent tx 0
                chainStateCursor.TryAddUnspentTx(unspentTx0);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                // add unspent tx 1
                chainStateCursor.TryAddUnspentTx(unspentTx1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                // remove unspent tx 1
                chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));

                // remove unspent tx 0
                chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash);

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx0.TxHash));
                Assert.IsFalse(chainStateCursor.ContainsUnspentTx(unspentTx1.TxHash));
            }
        }
        private void TestCommitTransaction(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Spent));
            var spentTxes = BlockSpentTxes.CreateRange(new[] { unspentTx.ToSpentTx() });

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // add data
                chainStateCursor.ChainTip = chainedHeader0;
                chainStateCursor.TryAddUnspentTx(unspentTx);
                chainStateCursor.UnspentTxCount++;
                chainStateCursor.TryAddBlockSpentTxes(0, spentTxes);

                // verify data
                Assert.AreEqual(chainedHeader0, chainStateCursor.ChainTip);
                Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                UnspentTx actualUnspentTx;
                Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                Assert.AreEqual(unspentTx, actualUnspentTx);

                BlockSpentTxes actualSpentTxes;
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                CollectionAssert.AreEqual(spentTxes.ToList(), actualSpentTxes.ToList());

                // commit transaction
                chainStateCursor.CommitTransaction();

                chainStateCursor.BeginTransaction();

                // verify data
                Assert.AreEqual(chainedHeader0, chainStateCursor.ChainTip);
                Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                Assert.AreEqual(unspentTx, actualUnspentTx);

                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes));
                CollectionAssert.AreEqual(spentTxes.ToList(), actualSpentTxes.ToList());

                chainStateCursor.RollbackTransaction();
            }
        }
        public void TestTryAddGetRemoveBlockUnmintedTxes(ITestStorageProvider provider)
        {
            var unmintedTxes0 = ImmutableList.Create(
                new UnmintedTx(txHash: (UInt256)0,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 0),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 1),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 2))),
                new UnmintedTx(txHash: (UInt256)1,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 3),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 4),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 5))));

            var unmintedTxes1 = ImmutableList.Create(
                new UnmintedTx(txHash: (UInt256)2,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 0),
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 1))),
                new UnmintedTx(txHash: (UInt256)3,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 2),
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 3))));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial empty state
                IImmutableList<UnmintedTx> actualUnmintedTxes0, actualUnmintedTxes1;
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)0, out actualUnmintedTxes0));
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)1, out actualUnmintedTxes1));

                // add unminted txes 0
                Assert.IsTrue(chainStateCursor.TryAddBlockUnmintedTxes((UInt256)0, unmintedTxes0));

                // verify unminted txes
                Assert.IsTrue(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)0, out actualUnmintedTxes0));
                CollectionAssert.AreEqual(unmintedTxes0.ToList(), actualUnmintedTxes0.ToList());
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)1, out actualUnmintedTxes1));

                // add unminted txes 1
                Assert.IsTrue(chainStateCursor.TryAddBlockUnmintedTxes((UInt256)1, unmintedTxes1));

                // verify unminted txes
                Assert.IsTrue(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)0, out actualUnmintedTxes0));
                CollectionAssert.AreEqual(unmintedTxes0.ToList(), actualUnmintedTxes0.ToList());
                Assert.IsTrue(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)1, out actualUnmintedTxes1));
                CollectionAssert.AreEqual(unmintedTxes1.ToList(), actualUnmintedTxes1.ToList());

                // remove unminted txes 1
                Assert.IsTrue(chainStateCursor.TryRemoveBlockUnmintedTxes((UInt256)1));

                // verify unminted txes
                Assert.IsTrue(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)0, out actualUnmintedTxes0));
                CollectionAssert.AreEqual(unmintedTxes0.ToList(), actualUnmintedTxes0.ToList());
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)1, out actualUnmintedTxes1));

                // remove unminted txes 0
                Assert.IsTrue(chainStateCursor.TryRemoveBlockUnmintedTxes((UInt256)0));

                // verify unminted txes
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)0, out actualUnmintedTxes0));
                Assert.IsFalse(chainStateCursor.TryGetBlockUnmintedTxes((UInt256)1, out actualUnmintedTxes1));
            }
        }
Beispiel #38
0
        private void TestRollback(ITestStorageProvider provider)
        {
            ConsoleLoggingModule.Configure();
            var logger = LogManager.GetCurrentClassLogger();

            var blockCount = 10.THOUSAND();
            var checkUtxoHashFrequencey = 1000;

            var blockProvider = new TestNet3BlockProvider();
            var blocks        = blockProvider.ReadBlocks().Take(blockCount).ToList();

            var genesisBlock  = blocks[0];
            var genesisHeader = new ChainedHeader(genesisBlock.Header, height: 0, totalWork: 0, dateSeen: DateTimeOffset.Now);
            var genesisChain  = Chain.CreateForGenesisBlock(genesisHeader);

            var chainParams = new Testnet3Params();
            var rules       = new CoreRules(chainParams)
            {
                IgnoreScripts      = true,
                IgnoreSignatures   = true,
                IgnoreScriptErrors = true
            };

            using (var storageManager = provider.OpenStorageManager())
                using (var coreStorage = new CoreStorage(storageManager))
                    using (var chainStateBuilder = new ChainStateBuilder(rules, coreStorage, storageManager))
                    {
                        // add blocks to storage
                        coreStorage.AddGenesisBlock(ChainedHeader.CreateForGenesisBlock(blocks[0].Header));
                        foreach (var block in blocks)
                        {
                            coreStorage.TryAddBlock(block);
                        }

                        // store empty utxo hash
                        var expectedUtxoHashes = new List <UInt256>();
                        using (var chainState = chainStateBuilder.ToImmutable())
                            expectedUtxoHashes.Add(UtxoCommitment.ComputeHash(chainState));

                        // calculate utxo forward and store its state at each step along the way
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            logger.Info($"Adding: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);

                            chainStateBuilder.AddBlockAsync(chainedHeader, block.Transactions.Select(
                                                                (tx, txIndex) => BlockTx.Create(txIndex, tx))).Wait();

                            if (blockIndex % checkUtxoHashFrequencey == 0 || blockIndex == blocks.Count - 1)
                            {
                                using (var chainState = chainStateBuilder.ToImmutable())
                                    expectedUtxoHashes.Add(UtxoCommitment.ComputeHash(chainState));
                            }
                        }

                        // verify the utxo state before rolling back
                        var expectedLastUtxoHash = UInt256.ParseHex("5f155c7d8a5c850d5fb2566aec5110caa40e270184126d17022ae9780fd65fd9");
                        Assert.AreEqual(expectedLastUtxoHash, expectedUtxoHashes.Last());
                        expectedUtxoHashes.RemoveAt(expectedUtxoHashes.Count - 1);

                        // roll utxo backwards and validate its state at each step along the way
                        for (var blockIndex = blocks.Count - 1; blockIndex >= 0; blockIndex--)
                        {
                            logger.Info($"Rolling back: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);
                            var blockTxes     = block.Transactions.Select((tx, txIndex) => BlockTx.Create(txIndex, tx));

                            chainStateBuilder.RollbackBlock(chainedHeader, blockTxes);

                            if ((blockIndex - 1) % checkUtxoHashFrequencey == 0 || blockIndex == 0)
                            {
                                var expectedUtxoHash = expectedUtxoHashes.Last();
                                expectedUtxoHashes.RemoveAt(expectedUtxoHashes.Count - 1);

                                using (var chainState = chainStateBuilder.ToImmutable())
                                    Assert.AreEqual(expectedUtxoHash, UtxoCommitment.ComputeHash(chainState));
                            }
                        }

                        // verify chain state was rolled all the way back
                        Assert.AreEqual(-1, chainStateBuilder.Chain.Height);
                        Assert.AreEqual(0, expectedUtxoHashes.Count);

                        // calculate utxo forward again
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            logger.Info($"Adding: {blockIndex:N0}");

                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0, DateTimeOffset.Now);

                            chainStateBuilder.AddBlockAsync(chainedHeader, block.Transactions.Select(
                                                                (tx, txIndex) => BlockTx.Create(txIndex, tx))).Wait();
                        }

                        // verify final utxo state again
                        using (var chainState = chainStateBuilder.ToImmutable())
                            Assert.AreEqual(expectedLastUtxoHash, UtxoCommitment.ComputeHash(chainState));
                    }
        }
        private void TestRollback(ITestStorageProvider provider)
        {
            var logger = LogManager.CreateNullLogger();
            var sha256 = new SHA256Managed();

            var blockProvider = new MainnetBlockProvider();
            var blocks        = Enumerable.Range(0, 500).Select(x => blockProvider.GetBlock(x)).ToList();

            var genesisBlock  = blocks[0];
            var genesisHeader = new ChainedHeader(genesisBlock.Header, height: 0, totalWork: 0);
            var genesisChain  = Chain.CreateForGenesisBlock(genesisHeader);

            var rules = new MainnetRules(logger);

            using (var storageManager = provider.OpenStorageManager())
                using (var coreStorage = new CoreStorage(storageManager, logger))
                    using (var chainStateBuilder = new ChainStateBuilder(logger, rules, coreStorage))
                    {
                        // add blocks to storage
                        coreStorage.AddGenesisBlock(ChainedHeader.CreateForGenesisBlock(blocks[0].Header));
                        foreach (var block in blocks)
                        {
                            coreStorage.TryAddBlock(block);
                        }

                        // calculate utxo forward and store its state at each step along the way
                        var expectedUtxos = new List <List <UnspentTx> >();
                        for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
                        {
                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0);

                            chainStateBuilder.AddBlock(chainedHeader, block.Transactions);

                            using (var chainState = chainStateBuilder.ToImmutable())
                            {
                                expectedUtxos.Add(chainState.ReadUnspentTransactions().ToList());
                            }
                        }

                        // verify the utxo state before rolling back
                        //TODO verify the UTXO hash hard-coded here is correct
                        var expectedUtxoHash = UInt256.Parse("609eb5882e0b71a707fb876c844fbfe6b4579e04eb27c7c0cefbb7478bac737b", NumberStyles.HexNumber);
                        using (var utxoStream = new UtxoStream(logger, expectedUtxos.Last()))
                        {
                            var utxoHash = new UInt256(sha256.ComputeDoubleHash(utxoStream));
                            Assert.AreEqual(expectedUtxoHash, utxoHash);
                        }
                        expectedUtxos.RemoveAt(expectedUtxos.Count - 1);

                        // roll utxo backwards and validate its state at each step along the way
                        for (var blockIndex = blocks.Count - 1; blockIndex >= 1; blockIndex--)
                        {
                            var block         = blocks[blockIndex];
                            var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0);
                            var blockTxes     = block.Transactions.Select((tx, txIndex) => new BlockTx(txIndex, 0, tx.Hash, /*pruned:*/ false, tx));

                            chainStateBuilder.RollbackBlock(chainedHeader, blockTxes);

                            var expectedUtxo = expectedUtxos.Last();
                            expectedUtxos.RemoveAt(expectedUtxos.Count - 1);

                            List <UnspentTx> actualUtxo;
                            using (var chainState = chainStateBuilder.ToImmutable())
                            {
                                actualUtxo = chainState.ReadUnspentTransactions().ToList();
                            }

                            CollectionAssert.AreEqual(expectedUtxo, actualUtxo, "UTXO differs at height: {0}".Format2(blockIndex));
                        }
                    }
        }
        // IBlockTxesStorage.Defragment
        private void TestDefragment(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                Assert.Inconclusive("TODO");
            }
        }
        private void TestTryUpdateUnspentTx(ITestStorageProvider provider)
        {
            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTxUpdated = unspentTx.SetOutputState(0, OutputState.Spent);
            Assert.AreNotEqual(unspentTx, unspentTxUpdated);

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify can't update missing unspent tx
                Assert.IsFalse(chainStateCursor.TryUpdateUnspentTx(unspentTx));

                // add unspent tx
                Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx));

                // verify unspent tx
                UnspentTx actualUnspentTx;
                Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                Assert.AreEqual(unspentTx, actualUnspentTx);

                // update unspent tx
                Assert.IsTrue(chainStateCursor.TryUpdateUnspentTx(unspentTxUpdated));

                // verify updated unspent tx
                Assert.IsTrue(chainStateCursor.TryGetUnspentTx(unspentTx.TxHash, out actualUnspentTx));
                Assert.AreEqual(unspentTxUpdated, actualUnspentTx);

                // remove unspent tx
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx.TxHash));

                // verify can't update missing unspent tx
                Assert.IsFalse(chainStateCursor.TryUpdateUnspentTx(unspentTx));
            }
        }
 private void TestBeginTransaction(ITestStorageProvider provider)
 {
     Assert.Inconclusive("TODO");
 }
        /// <summary>
        /// Verify that chain state cursor does not allow write operations in read-only transaction.
        /// </summary>
        /// <param name="provider"></param>
        public void TestWriteOperationInReadonlyTransaction(ITestStorageProvider provider)
        {
            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                chainStateCursor.BeginTransaction(readOnly: true);

                var actions = new Action[]
                {
                    () => { chainStateCursor.ChainTip = RandomData.RandomChainedHeader(); },
                    () => { chainStateCursor.UnspentTxCount = 0; },
                    () => { chainStateCursor.UnspentOutputCount = 0; },
                    () => { chainStateCursor.TotalTxCount = 0; },
                    () => { chainStateCursor.TotalInputCount = 0; },
                    () => { chainStateCursor. TotalOutputCount = 0; },
                    () => { chainStateCursor.TryAddUnspentTx(unspentTx); },
                    () => { chainStateCursor.TryRemoveUnspentTx(UInt256.Zero); },
                    () => { chainStateCursor.TryUpdateUnspentTx(unspentTx); },
                    () => { chainStateCursor.TryAddBlockSpentTxes(0, BlockSpentTxes.CreateRange(Enumerable.Empty<SpentTx>())); },
                    () => { chainStateCursor.TryRemoveBlockSpentTxes(0); },
                    () => { chainStateCursor.TryAddBlockUnmintedTxes(UInt256.Zero  , ImmutableList<UnmintedTx>.Empty); },
                    () => { chainStateCursor.TryRemoveBlockUnmintedTxes(UInt256.Zero); },
                };

                foreach (var action in actions)
                    AssertMethods.AssertThrows<InvalidOperationException>(action);

                chainStateCursor.RollbackTransaction();
            }
        }
        private void TestUnspentTxCount(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: (UInt256)0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: (UInt256)1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx2 = new UnspentTx(txHash: (UInt256)2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial count
                Assert.AreEqual(0, chainStateCursor.UnspentTxCount);

                // increment count
                chainStateCursor.UnspentTxCount++;

                // verify count
                Assert.AreEqual(1, chainStateCursor.UnspentTxCount);

                // set count
                chainStateCursor.UnspentTxCount = 10;

                // verify count
                Assert.AreEqual(10, chainStateCursor.UnspentTxCount);
            }
        }
        private void TestChainTip(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();
            var chainedHeader1 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial tip
                Assert.IsNull(chainStateCursor.ChainTip);

                // set tip
                chainStateCursor.ChainTip = chainedHeader0;

                // verify tip
                Assert.AreEqual(chainedHeader0, chainStateCursor.ChainTip);

                // set tip
                chainStateCursor.ChainTip = chainedHeader1;

                // verify tip
                Assert.AreEqual(chainedHeader1, chainStateCursor.ChainTip);
            }
        }
        public void TestContainsBlockSpentTxes(ITestStorageProvider provider)
        {
            var spentTxes0 = BlockSpentTxes.CreateRange(new[] {
                new SpentTx((UInt256)0, 0, 0),
                new SpentTx((UInt256)1, 0, 1),
                new SpentTx((UInt256)2, 0, 2)});
            var spentTxes1 = BlockSpentTxes.CreateRange(new[] {
                new SpentTx((UInt256)100, 0, 100),
                new SpentTx((UInt256)101, 0, 101)});

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(0));
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                // add spent txes 0
                chainStateCursor.TryAddBlockSpentTxes(0, spentTxes0);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                // add unspent tx 1
                chainStateCursor.TryAddBlockSpentTxes(1, spentTxes1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(1));

                // remove unspent tx 1
                chainStateCursor.TryRemoveBlockSpentTxes(1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockSpentTxes(0));
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));

                // remove unspent tx 0
                chainStateCursor.TryRemoveBlockSpentTxes(0);

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(0));
                Assert.IsFalse(chainStateCursor.ContainsBlockSpentTxes(1));
            }
        }
        private void TestContainsHeader(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var header0 = fakeHeaders.GenesisChained();
            var header1 = fakeHeaders.NextChained();

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsHeader(header0.Hash));
                Assert.IsFalse(chainStateCursor.ContainsHeader(header1.Hash));

                // add header 0
                chainStateCursor.TryAddHeader(header0);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsHeader(header0.Hash));
                Assert.IsFalse(chainStateCursor.ContainsHeader(header1.Hash));

                // add header 1
                chainStateCursor.TryAddHeader(header1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsHeader(header0.Hash));
                Assert.IsTrue(chainStateCursor.ContainsHeader(header1.Hash));

                // remove header 1
                chainStateCursor.TryRemoveHeader(header1.Hash);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsHeader(header0.Hash));
                Assert.IsFalse(chainStateCursor.ContainsHeader(header1.Hash));

                // remove header 0
                chainStateCursor.TryRemoveHeader(header0.Hash);

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsHeader(header0.Hash));
                Assert.IsFalse(chainStateCursor.ContainsHeader(header1.Hash));
            }
        }
        public void TestContainsBlockUnmintedTxes(ITestStorageProvider provider)
        {
            var unmintedTxes0 = ImmutableList.Create(
                new UnmintedTx(txHash: (UInt256)0,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 0),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 1),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 2))),
                new UnmintedTx(txHash: (UInt256)1,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 3),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 4),
                        new TxLookupKey(blockHash: (UInt256)0, txIndex: 5))));

            var unmintedTxes1 = ImmutableList.Create(
                new UnmintedTx(txHash: (UInt256)2,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 0),
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 1))),
                new UnmintedTx(txHash: (UInt256)3,
                    prevOutputTxKeys: ImmutableArray.Create(
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 2),
                        new TxLookupKey(blockHash: (UInt256)1, txIndex: 3))));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)0));
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)1));

                // add unminted txes 0
                chainStateCursor.TryAddBlockUnmintedTxes((UInt256)0, unmintedTxes0);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)0));
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)1));

                // add ununminted tx 1
                chainStateCursor.TryAddBlockUnmintedTxes((UInt256)1, unmintedTxes1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)0));
                Assert.IsTrue(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)1));

                // remove ununminted tx 1
                chainStateCursor.TryRemoveBlockUnmintedTxes((UInt256)1);

                // verify presence
                Assert.IsTrue(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)0));
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)1));

                // remove ununminted tx 0
                chainStateCursor.TryRemoveBlockUnmintedTxes((UInt256)0);

                // verify presence
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)0));
                Assert.IsFalse(chainStateCursor.ContainsBlockUnmintedTxes((UInt256)1));
            }
        }
        private void TestInTransaction(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // verify initial InTransaction=false
                Assert.IsFalse(chainStateCursor.InTransaction);

                // begin transaction and verify InTransaction=true
                chainStateCursor.BeginTransaction();
                Assert.IsTrue(chainStateCursor.InTransaction);

                // rollback transaction and verify InTransaction=false
                chainStateCursor.RollbackTransaction();
                Assert.IsFalse(chainStateCursor.InTransaction);

                // begin transaction and verify InTransaction=true
                chainStateCursor.BeginTransaction();
                Assert.IsTrue(chainStateCursor.InTransaction);

                // commit transaction and verify InTransaction=false
                chainStateCursor.CommitTransaction();
                Assert.IsFalse(chainStateCursor.InTransaction);
            }
        }
        public void TestAccessAcrossThreads(ITestStorageProvider provider)
        {
            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            using (var thread1Done = new AutoResetEvent(false))
            using (var thread2Done = new AutoResetEvent(false))
            {
                var chainStateCursor = handle.Item;

                var thread1Actions = new BlockingCollection<Action>();
                var thread2Actions = new BlockingCollection<Action>();

                var thread1 = new Thread(() =>
                    {
                        foreach (var action in thread1Actions.GetConsumingEnumerable())
                        {
                            action();
                            thread1Done.Set();
                        }
                    });

                var thread2 = new Thread(() =>
                {
                    foreach (var action in thread2Actions.GetConsumingEnumerable())
                    {
                        action();
                        thread2Done.Set();
                    }
                });

                thread1.Start();
                thread2.Start();

                // begin transaction on thread #1
                thread1Actions.Add(() =>
                    chainStateCursor.BeginTransaction());
                thread1Done.WaitOne();

                // commit transaction on thread #2
                thread2Actions.Add(() =>
                    chainStateCursor.CommitTransaction());
                thread2Done.WaitOne();

                // begin transaction on thread #1
                thread1Actions.Add(() =>
                    chainStateCursor.BeginTransaction());
                thread1Done.WaitOne();

                // rollback transaction on thread #2
                thread2Actions.Add(() =>
                    chainStateCursor.RollbackTransaction());
                thread2Done.WaitOne();

                thread1Actions.CompleteAdding();
                thread2Actions.CompleteAdding();

                thread1.Join();
                thread2.Join();
            }
        }
        private void TestTransactionIsolation(ITestStorageProvider provider)
        {
            var fakeHeaders = new FakeHeaders();
            var chainedHeader0 = fakeHeaders.GenesisChained();

            // open two chain state cursors
            using (var storageManager = provider.OpenStorageManager())
            using (var txBeganEvent = new ManualResetEventSlim())
            using (var headerAddedEvent = new ManualResetEventSlim())
            using (var doCommitEvent = new ManualResetEventSlim())
            using (var committedEvent = new ManualResetEventSlim())
            {
                var thread1 = new Thread(() =>
                {
                    using (var handle1 = storageManager.OpenChainStateCursor())
                    {
                        var chainStateCursor1 = handle1.Item;

                        // open transactions on cusor 1
                        chainStateCursor1.BeginTransaction();

                        // add a header on cursor 1
                        chainStateCursor1.ChainTip = chainedHeader0;

                        // alert header has been added
                        headerAddedEvent.Set();

                        doCommitEvent.Wait();

                        // commit transaction on cursor 1
                        chainStateCursor1.CommitTransaction();

                        // alert transaction has been committed
                        committedEvent.Set();
                    }
                });
                thread1.Start();

                // wait for header to be added on cursor 1
                headerAddedEvent.Wait();

                using (var handle2 = storageManager.OpenChainStateCursor())
                {
                    var chainStateCursor2 = handle2.Item;

                    // open transactions on cusor 2
                    chainStateCursor2.BeginTransaction(readOnly: true);

                    // verify empty chain
                    Assert.IsNull(chainStateCursor2.ChainTip);

                    doCommitEvent.Set();
                    committedEvent.Wait();

                    // verify empty chain
                    Assert.IsNull(chainStateCursor2.ChainTip);

                    chainStateCursor2.CommitTransaction();
                    chainStateCursor2.BeginTransaction();

                    // verify cursor 2 now sees the new header
                    Assert.AreEqual(chainedHeader0, chainStateCursor2.ChainTip);

                    chainStateCursor2.RollbackTransaction();
                }

                thread1.Join();
            }
        }
 public void TestDefragment(ITestStorageProvider provider)
 {
     Assert.Inconclusive("TODO");
 }
        // IBlockTxesStorage.ContainsBlock
        private void TestContainsBlock(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // block should not be present
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));

                // add the block
                blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                // block should be present
                Assert.IsTrue(blockTxesStorage.ContainsBlock(block.Hash));

                // remove the block
                blockTxesStorage.TryRemoveBlockTransactions(block.Hash);

                // block should not be present
                Assert.IsFalse(blockTxesStorage.ContainsBlock(block.Hash));
            }
        }
 public void TestFlush(ITestStorageProvider provider)
 {
     Assert.Inconclusive("TODO");
 }
        // IBlockTxesStorage.TryGetTransaction
        private void TestTryGetTransaction(ITestStorageProvider provider)
        {
            using (var storageManager = provider.OpenStorageManager())
            {
                var blockTxesStorage = storageManager.BlockTxesStorage;

                // create a block
                var block = CreateFakeBlock();

                // add block transactions
                blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                // verify missing transactions
                BlockTx transaction;
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(UInt256.Zero, 0, out transaction));
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(block.Hash, -1, out transaction));
                Assert.IsFalse(blockTxesStorage.TryGetTransaction(block.Hash, block.Transactions.Length, out transaction));

                // verify transactions
                for (var txIndex = 0; txIndex < block.Transactions.Length; txIndex++)
                {
                    Assert.IsTrue(blockTxesStorage.TryGetTransaction(block.Hash, txIndex, out transaction));
                    Assert.AreEqual(block.Transactions[txIndex].Hash, transaction.Hash);
                    Assert.AreEqual(transaction.Hash, new UInt256(SHA256Static.ComputeDoubleHash(transaction.TxBytes.ToArray())));
                }
            }
        }
        /// <summary>
        /// Verify that chain state cursor does not allow use outside of a transaction.
        /// </summary>
        /// <param name="provider"></param>
        public void TestOperationOutsideTransaction(ITestStorageProvider provider)
        {
            var unspentTx = new UnspentTx(txHash: UInt256.Zero, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                Assert.IsFalse(chainStateCursor.InTransaction);

                var actions = new Action[]
                {
                    () => { var x = chainStateCursor.ChainTip; },
                    () => { chainStateCursor.ChainTip = RandomData.RandomChainedHeader(); },
                    () => { var x = chainStateCursor.UnspentTxCount; },
                    () => { chainStateCursor.UnspentTxCount = 0; },
                    () => { var x = chainStateCursor.UnspentOutputCount; },
                    () => { chainStateCursor.UnspentOutputCount = 0; },
                    () => { var x = chainStateCursor.TotalTxCount; },
                    () => { chainStateCursor.TotalTxCount = 0; },
                    () => { var x = chainStateCursor.TotalInputCount; },
                    () => { chainStateCursor.TotalInputCount = 0; },
                    () => { var x = chainStateCursor. TotalOutputCount; },
                    () => { chainStateCursor. TotalOutputCount = 0; },
                    () => { var x = chainStateCursor.ContainsUnspentTx(UInt256.Zero); },
                    () => { UnspentTx _; chainStateCursor.TryGetUnspentTx(UInt256.Zero, out _); },
                    () => { chainStateCursor.TryAddUnspentTx(unspentTx); },
                    () => { chainStateCursor.TryRemoveUnspentTx(UInt256.Zero); },
                    () => { chainStateCursor.TryUpdateUnspentTx(unspentTx); },
                    () => { chainStateCursor.ReadUnspentTransactions(); },
                    () => { chainStateCursor.ContainsBlockSpentTxes(0); },
                    () => { BlockSpentTxes _; chainStateCursor.TryGetBlockSpentTxes(0, out _); },
                    () => { chainStateCursor.TryAddBlockSpentTxes(0, BlockSpentTxes.CreateRange(Enumerable.Empty<SpentTx>())); },
                    () => { chainStateCursor.TryRemoveBlockSpentTxes(0); },
                    () => { chainStateCursor.ContainsBlockUnmintedTxes(UInt256.Zero); },
                    () => { IImmutableList<UnmintedTx> _; chainStateCursor.TryGetBlockUnmintedTxes(UInt256.Zero, out _); },
                    () => { chainStateCursor.TryAddBlockUnmintedTxes(UInt256.Zero  , ImmutableList<UnmintedTx>.Empty); },
                    () => { chainStateCursor.TryRemoveBlockUnmintedTxes(UInt256.Zero); },
                };

                foreach (var action in actions)
                    AssertMethods.AssertThrows<InvalidOperationException>(action);
            }
        }
        // IBlockTxesStorage.PruneElements
        private void TestPruneElements(ITestStorageProvider provider)
        {
            // run 4 iterations of pruning: no adjacent blocks, one adjacent block on either side, and two adjacent blocks
            for (var iteration = 0; iteration < 4; iteration++)
            {
                provider.TestCleanup();

                using (var kernel = new StandardKernel())
                using (var storageManager = provider.OpenStorageManager())
                {
                    // add logging module
                    kernel.Load(new ConsoleLoggingModule(LogLevel.Debug));

                    var blockTxesStorage = storageManager.BlockTxesStorage;

                    // create a block
                    var block = CreateFakeBlock();
                    var txCount = block.Transactions.Length;

                    // determine expected merkle root node when fully pruned
                    var expectedFinalDepth = (int)Math.Ceiling(Math.Log(txCount, 2));
                    var expectedFinalElement = new BlockTxNode(index: 0, depth: expectedFinalDepth, hash: block.Header.MerkleRoot, pruned: true, encodedTx: null);

                    // pick a random pruning order
                    var random = new Random();
                    var pruneOrderSource = Enumerable.Range(0, txCount).ToList();
                    var pruneOrder = new List<int>(txCount);
                    while (pruneOrderSource.Count > 0)
                    {
                        var randomIndex = random.Next(pruneOrderSource.Count);

                        pruneOrder.Add(pruneOrderSource[randomIndex]);
                        pruneOrderSource.RemoveAt(randomIndex);
                    }

                    // add preceding block
                    if (iteration == 1 || iteration == 3)
                        blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() - 1), block.BlockTxes);

                    // add the block to be pruned
                    blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                    // add proceeding block
                    if (iteration == 2 || iteration == 3)
                        blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() + 1), block.BlockTxes);

                    // prune the block
                    var count = 0;
                    foreach (var pruneIndex in pruneOrder)
                    {
                        Debug.WriteLine(count++);

                        // prune a transaction
                        blockTxesStorage.PruneElements(new[] { new KeyValuePair<UInt256, IEnumerable<int>>(block.Hash, new[] { pruneIndex }) });

                        // read block transactions
                        IEnumerator<BlockTxNode> blockTxNodes;
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out blockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, blockTxNodes.UsingAsEnumerable()).Count();
                    }

                    // read fully pruned block and verify
                    IEnumerator<BlockTxNode> finalBlockTxNodes;
                    Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out finalBlockTxNodes));
                    var finalNodes = MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).ToList();
                    Assert.AreEqual(1, finalNodes.Count);
                    Assert.AreEqual(expectedFinalElement, finalNodes[0]);

                    // verify preceding block was not affected
                    if (iteration == 1 || iteration == 3)
                    {
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() - 1), out finalBlockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                    }

                    // verify proceeding block was not affected
                    if (iteration == 2 || iteration == 3)
                    {
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() + 1), out finalBlockTxNodes));

                        // verify block transactions, exception will be fired if invalid
                        Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                    }
                }
            }
        }
        public void TestReadUnspentTransactions(ITestStorageProvider provider)
        {
            var unspentTx0 = new UnspentTx(txHash: (UInt256)0, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx1 = new UnspentTx(txHash: (UInt256)1, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));
            var unspentTx2 = new UnspentTx(txHash: (UInt256)2, blockIndex: 0, txIndex: 0, outputStates: new OutputStates(1, OutputState.Unspent));

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial empty state
                Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count());

                // add unspent tx 0
                Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx0));

                // verify unspent txes
                CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList());

                // add unspent tx 1
                Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx1));

                // verify unspent txes
                CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList());

                // add unspent tx 2
                Assert.IsTrue(chainStateCursor.TryAddUnspentTx(unspentTx2));

                // verify unspent txes
                CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1, unspentTx2 }, chainStateCursor.ReadUnspentTransactions().ToList());

                // remove unspent tx 2
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx2.TxHash));

                // verify unspent txes
                CollectionAssert.AreEquivalent(new[] { unspentTx0, unspentTx1 }, chainStateCursor.ReadUnspentTransactions().ToList());

                // remove unspent tx 1
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx1.TxHash));

                // verify unspent txes
                CollectionAssert.AreEquivalent(new[] { unspentTx0 }, chainStateCursor.ReadUnspentTransactions().ToList());

                // remove unspent tx 0
                Assert.IsTrue(chainStateCursor.TryRemoveUnspentTx(unspentTx0.TxHash));

                // verify unspent txes
                Assert.AreEqual(0, chainStateCursor.ReadUnspentTransactions().Count());
            }
        }
        public void TestTryAddGetRemoveBlockSpentTxes(ITestStorageProvider provider)
        {
            var spentTxes0 = BlockSpentTxes.CreateRange(new[] {
                new SpentTx((UInt256)0, 0, 0),
                new SpentTx((UInt256)1, 0, 1),
                new SpentTx((UInt256)2, 0, 2)});
            var spentTxes1 = BlockSpentTxes.CreateRange(new[] {
                new SpentTx((UInt256)100, 0, 100),
                new SpentTx((UInt256)101, 0, 101)});

            using (var storageManager = provider.OpenStorageManager())
            using (var handle = storageManager.OpenChainStateCursor())
            {
                var chainStateCursor = handle.Item;

                // begin transaction
                chainStateCursor.BeginTransaction();

                // verify initial empty state
                BlockSpentTxes actualSpentTxes0, actualSpentTxes1;
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                // add spent txes 0
                Assert.IsTrue(chainStateCursor.TryAddBlockSpentTxes(0, spentTxes0));

                // verify spent txes
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                CollectionAssert.AreEqual(spentTxes0.ToList(), actualSpentTxes0.ToList());
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                // add spent txes 1
                Assert.IsTrue(chainStateCursor.TryAddBlockSpentTxes(1, spentTxes1));

                // verify spent txes
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                CollectionAssert.AreEqual(spentTxes0.ToList(), actualSpentTxes0.ToList());
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));
                CollectionAssert.AreEqual(spentTxes1.ToList(), actualSpentTxes1.ToList());

                // remove spent txes 1
                Assert.IsTrue(chainStateCursor.TryRemoveBlockSpentTxes(1));

                // verify spent txes
                Assert.IsTrue(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                CollectionAssert.AreEqual(spentTxes0.ToList(), actualSpentTxes0.ToList());
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));

                // remove spent txes 0
                Assert.IsTrue(chainStateCursor.TryRemoveBlockSpentTxes(0));

                // verify spent txes
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(0, out actualSpentTxes0));
                Assert.IsFalse(chainStateCursor.TryGetBlockSpentTxes(1, out actualSpentTxes1));
            }
        }
        // IBlockTxesStorage.PruneElements
        private void TestPruneElements(ITestStorageProvider provider)
        {
            // run 4 iterations of pruning: no adjacent blocks, one adjacent block on either side, and two adjacent blocks
            for (var iteration = 0; iteration < 4; iteration++)
            {
                provider.TestCleanup();

                using (var kernel = new StandardKernel())
                    using (var storageManager = provider.OpenStorageManager())
                    {
                        // add logging module
                        kernel.Load(new ConsoleLoggingModule(LogLevel.Debug));

                        var blockTxesStorage = storageManager.BlockTxesStorage;

                        // create a block
                        var block   = CreateFakeBlock();
                        var txCount = block.Transactions.Length;

                        // determine expected merkle root node when fully pruned
                        var expectedFinalDepth   = (int)Math.Ceiling(Math.Log(txCount, 2));
                        var expectedFinalElement = new BlockTxNode(index: 0, depth: expectedFinalDepth, hash: block.Header.MerkleRoot, pruned: true, encodedTx: null);

                        // pick a random pruning order
                        var random           = new Random();
                        var pruneOrderSource = Enumerable.Range(0, txCount).ToList();
                        var pruneOrder       = new List <int>(txCount);
                        while (pruneOrderSource.Count > 0)
                        {
                            var randomIndex = random.Next(pruneOrderSource.Count);

                            pruneOrder.Add(pruneOrderSource[randomIndex]);
                            pruneOrderSource.RemoveAt(randomIndex);
                        }

                        // add preceding block
                        if (iteration == 1 || iteration == 3)
                        {
                            blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() - 1), block.BlockTxes);
                        }

                        // add the block to be pruned
                        blockTxesStorage.TryAddBlockTransactions(block.Hash, block.BlockTxes);

                        // add proceeding block
                        if (iteration == 2 || iteration == 3)
                        {
                            blockTxesStorage.TryAddBlockTransactions(new UInt256(block.Hash.ToBigInteger() + 1), block.BlockTxes);
                        }

                        // prune the block
                        var count = 0;
                        foreach (var pruneIndex in pruneOrder)
                        {
                            Debug.WriteLine(count++);

                            // prune a transaction
                            blockTxesStorage.PruneElements(new[] { new KeyValuePair <UInt256, IEnumerable <int> >(block.Hash, new[] { pruneIndex }) });

                            // read block transactions
                            IEnumerator <BlockTxNode> blockTxNodes;
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out blockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, blockTxNodes.UsingAsEnumerable()).Count();
                        }

                        // read fully pruned block and verify
                        IEnumerator <BlockTxNode> finalBlockTxNodes;
                        Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(block.Hash, out finalBlockTxNodes));
                        var finalNodes = MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).ToList();
                        Assert.AreEqual(1, finalNodes.Count);
                        Assert.AreEqual(expectedFinalElement, finalNodes[0]);

                        // verify preceding block was not affected
                        if (iteration == 1 || iteration == 3)
                        {
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() - 1), out finalBlockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                        }

                        // verify proceeding block was not affected
                        if (iteration == 2 || iteration == 3)
                        {
                            Assert.IsTrue(blockTxesStorage.TryReadBlockTxNodes(new UInt256(block.Hash.ToBigInteger() + 1), out finalBlockTxNodes));

                            // verify block transactions, exception will be fired if invalid
                            Assert.AreEqual(block.Transactions.Length, MerkleTree.ReadMerkleTreeNodes(block.Header.MerkleRoot, finalBlockTxNodes.UsingAsEnumerable()).Count());
                        }
                    }
            }
        }