// 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()))); } } }
// 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)); } }
// 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)); } }
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); } }
// 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)); ; } }
// IBlockStorage.Defragment private void TestDefragment(ITestStorageProvider provider) { using (var storageManager = provider.OpenStorageManager()) { var blockStorage = storageManager.BlockStorage; Assert.Inconclusive("TODO"); } }
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)); } }
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()); } }
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()); } }
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)); } }
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); } }
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()); } }
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)); } }
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)); } }
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); } }
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)); } }
// 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()); } }
// 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); } }
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()); } }
// 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); } }
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()); } }
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)); } }
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)); } }
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()); } } } }