public BlockStoreTests()
        {
            this.network = KnownNetworks.StratisMain;
            this.repositoryTipHashAndHeight = new HashHeightPair(this.network.GenesisHash, 0);
            this.storeSettings = new StoreSettings(NodeSettings.Default(this.network));

            this.random = new Random();

            this.listOfSavedBlocks = new Dictionary <uint256, Block>();
            this.listOfSavedBlocks.Add(uint256.One, Block.Parse(this.testBlockHex, KnownNetworks.StratisMain.Consensus.ConsensusFactory));

            this.chainIndexer = CreateChain(10);

            this.nodeLifetime = new NodeLifetime();

            this.blockRepositoryMock = new Mock <IBlockRepository>();
            this.blockRepositoryMock.Setup(x => x.PutBlocks(It.IsAny <HashHeightPair>(), It.IsAny <List <Block> >()))
            .Callback((HashHeightPair newTip, List <Block> blocks) =>
            {
                this.repositoryTipHashAndHeight = newTip;
                this.repositorySavesCount++;
                this.repositoryTotalBlocksSaved += blocks.Count;
            });

            this.blockRepositoryMock.Setup(x => x.Delete(It.IsAny <HashHeightPair>(), It.IsAny <List <uint256> >()))
            .Callback((HashHeightPair newTip, List <uint256> blocks) =>
            {
                this.repositoryTotalBlocksDeleted += blocks.Count;
            });

            this.blockRepositoryMock.Setup(x => x.GetBlock(It.IsAny <uint256>()))
            .Returns((uint256 hash) =>
            {
                Block block = null;

                if (this.listOfSavedBlocks.ContainsKey(hash))
                {
                    block = this.listOfSavedBlocks[hash];
                }

                return(block);
            });

            this.blockRepositoryMock.Setup(x => x.TipHashAndHeight).Returns(() =>
            {
                return(this.repositoryTipHashAndHeight);
            });

            this.chainState = new ChainState();
            this.initialBlockDownloadState = new Mock <IInitialBlockDownloadState>();

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState, this.initialBlockDownloadState.Object);

            this.loggerFactory = new LoggerFactory();
            this.signals       = new Signals.Signals(this.loggerFactory, null);
            this.asyncProvider = new AsyncProvider(this.loggerFactory, this.signals, this.nodeLifetime);

            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushCondition, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);
        }
        public async Task BatchIsSavedOnShutdownAsync()
        {
            this.repositoryTipHashAndHeight = new HashHeightPair(this.chainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushConditionMock = new Mock <IBlockStoreQueueFlushCondition>();

            blockStoreFlushConditionMock.Setup(s => s.ShouldFlush).Returns(false);
            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushConditionMock.Object, this.storeSettings, this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();

            ChainedHeader lastHeader = null;

            for (int i = 1; i < this.chainIndexer.Height - 1; i++)
            {
                lastHeader = this.chainIndexer.GetHeader(i);
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, lastHeader));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(this.chainState.BlockStoreTip, this.chainIndexer.Genesis);
            Assert.Equal(0, this.repositorySavesCount);

            this.nodeLifetime.StopApplication();
            this.blockStoreQueue.Dispose();

            Assert.Equal(this.chainState.BlockStoreTip, lastHeader);
            Assert.Equal(1, this.repositorySavesCount);
        }
Example #3
0
        public async Task BatchIsSavedAfterSizeThresholdReachedAsync()
        {
            Block block     = Block.Load(Encoders.Hex.DecodeData(this.testBlockHex), Network.StratisMain);
            int   blockSize = block.GetSerializedSize();

            this.consensusTip = null;

            int count = BlockStoreQueue.BatchThresholdSizeBytes / blockSize + 2;

            ConcurrentChain longChain = this.CreateChain(count);

            this.repositoryBlockHash = longChain.Genesis.HashBlock;

            this.blockStoreQueue = new BlockStoreQueue(this.repository, longChain, this.chainState, new StoreSettings(), new NodeLifetime(), new LoggerFactory());

            await this.blockStoreQueue.InitializeAsync().ConfigureAwait(false);

            this.consensusTip = longChain.Tip;

            // Send all the blocks to the block store except for the last one because that will trigger batch saving because of reaching the tip.
            for (int i = 1; i < count; i++)
            {
                ChainedHeader header = longChain.GetBlock(i);

                this.blockStoreQueue.AddToPending(new BlockPair(block, header));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(longChain.GetBlock(count - 1), this.chainState.BlockStoreTip);
            Assert.Equal(1, this.repositorySavesCount);
        }
        public async Task BatchIsSavedAfterSizeThresholdReachedAsync()
        {
            Block block     = Block.Load(Encoders.Hex.DecodeData(this.testBlockHex), KnownNetworks.StratisMain.Consensus.ConsensusFactory);
            int   blockSize = block.GetSerializedSize();

            this.chainState.ConsensusTip = null;

            int count = 5 * 1024 * 1024 / blockSize + 2;

            ChainIndexer longChainIndexer = this.CreateChain(count);

            this.repositoryTipHashAndHeight = new HashHeightPair(longChainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState, this.initialBlockDownloadState.Object);

            this.blockStoreQueue = new BlockStoreQueue(longChainIndexer, this.chainState, blockStoreFlushCondition, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();
            this.chainState.ConsensusTip = longChainIndexer.Tip;

            // Send all the blocks to the block store except for the last one because that will trigger batch saving because of reaching the tip.
            for (int i = 1; i < count; i++)
            {
                ChainedHeader header = longChainIndexer.GetHeader(i);

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, header));
            }

            await WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(longChainIndexer.GetHeader(count - 1), this.chainState.BlockStoreTip);
            Assert.Equal(1, this.repositorySavesCount);
        }
        public BlockStoreTests()
        {
            this.network = KnownNetworks.StratisMain;
            this.repositoryTipHashAndHeight = new HashHeightPair(this.network.GenesisHash, 0);

            var serializer = new DBreezeSerializer();

            serializer.Initialize(new StratisMain());

            this.random = new Random();

            this.listOfSavedBlocks = new Dictionary <uint256, Block>();
            this.listOfSavedBlocks.Add(uint256.One, Block.Parse(this.testBlockHex, KnownNetworks.StratisMain));

            this.chain = CreateChain(10);

            this.nodeLifetime = new NodeLifetime();

            this.blockRepositoryMock = new Mock <IBlockRepository>();
            this.blockRepositoryMock.Setup(x => x.PutAsync(It.IsAny <HashHeightPair>(), It.IsAny <List <Block> >()))
            .Returns((HashHeightPair newTip, List <Block> blocks) =>
            {
                this.repositoryTipHashAndHeight = newTip;
                this.repositorySavesCount++;
                this.repositoryTotalBlocksSaved += blocks.Count;
                return(Task.CompletedTask);
            });

            this.blockRepositoryMock.Setup(x => x.DeleteAsync(It.IsAny <HashHeightPair>(), It.IsAny <List <uint256> >()))
            .Returns((HashHeightPair newTip, List <uint256> blocks) =>
            {
                this.repositoryTotalBlocksDeleted += blocks.Count;
                return(Task.CompletedTask);
            });

            this.blockRepositoryMock.Setup(x => x.GetBlockAsync(It.IsAny <uint256>()))
            .Returns((uint256 hash) =>
            {
                Block block = null;

                if (this.listOfSavedBlocks.ContainsKey(hash))
                {
                    block = this.listOfSavedBlocks[hash];
                }

                return(Task.FromResult(block));
            });

            this.blockRepositoryMock.Setup(x => x.TipHashAndHeight).Returns(() =>
            {
                return(this.repositoryTipHashAndHeight);
            });

            this.chainState = new ChainState();

            var blockStoreFlushCondition = new BlockStoreQueueFlushCondition(this.chainState);

            this.blockStoreQueue = new BlockStoreQueue(this.chain, this.chainState, blockStoreFlushCondition, new StoreSettings(NodeSettings.Default(this.network)),
                                                       this.blockRepositoryMock.Object, new LoggerFactory(), new Mock <INodeStats>().Object);
        }
Example #6
0
        public BlockStoreTests()
        {
            this.listOfSavedBlocks = new Dictionary <uint256, Block>();
            this.listOfSavedBlocks.Add(uint256.One, Block.Parse(this.testBlockHex, KnownNetworks.StratisMain));

            this.network = KnownNetworks.StratisMain;

            this.chain        = this.CreateChain(10);
            this.consensusTip = null;

            this.nodeLifetime = new NodeLifetime();

            var blockRepositoryMock = new Mock <IBlockRepository>();

            blockRepositoryMock.Setup(x => x.PutAsync(It.IsAny <uint256>(), It.IsAny <List <Block> >()))
            .Returns((uint256 nextBlockHash, List <Block> blocks) =>
            {
                this.repositoryBlockHash = nextBlockHash;
                this.repositorySavesCount++;
                this.repositoryTotalBlocksSaved += blocks.Count;
                return(Task.CompletedTask);
            });

            blockRepositoryMock.Setup(x => x.DeleteAsync(It.IsAny <uint256>(), It.IsAny <List <uint256> >()))
            .Returns((uint256 nextBlockHash, List <uint256> blocks) =>
            {
                this.repositoryTotalBlocksDeleted += blocks.Count;
                return(Task.CompletedTask);
            });

            blockRepositoryMock.Setup(x => x.GetAsync(It.IsAny <uint256>()))
            .Returns((uint256 hash) =>
            {
                Block block = null;

                if (this.listOfSavedBlocks.ContainsKey(hash))
                {
                    block = this.listOfSavedBlocks[hash];
                }

                return(Task.FromResult(block));
            });

            blockRepositoryMock.Setup(x => x.BlockHash).Returns(() =>
            {
                return(this.repositoryBlockHash);
            });

            this.repository = blockRepositoryMock.Object;

            var chainStateMoq = new Mock <IChainState>();

            chainStateMoq.Setup(x => x.ConsensusTip).Returns(() => this.consensusTip);
            chainStateMoq.SetupProperty(x => x.BlockStoreTip, null);

            this.chainState = chainStateMoq.Object;

            this.blockStoreQueue = new BlockStoreQueue(this.repository, this.chain, this.chainState, new StoreSettings(), this.nodeLifetime, new LoggerFactory());
        }
        public async Task ReorgedBlocksAreNotSavedAsync()
        {
            this.repositoryTipHashAndHeight = new HashHeightPair(this.chainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushConditionMock = new Mock <IBlockStoreQueueFlushCondition>();

            blockStoreFlushConditionMock.Setup(s => s.ShouldFlush).Returns(false);
            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushConditionMock.Object, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();

            int reorgedChainLenght = 3;
            int realChainLenght    = 6;

            // First present a short chain.
            ChainIndexer alternativeChainIndexer = CreateChain(reorgedChainLenght);

            for (int i = 1; i < alternativeChainIndexer.Height; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, alternativeChainIndexer.GetHeader(i)));
            }

            // Present second chain which has more work and reorgs blocks from genesis.
            for (int i = 1; i < realChainLenght; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, this.chainIndexer.GetHeader(i)));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            Assert.Equal(this.chainState.BlockStoreTip, this.chainIndexer.Genesis);
            Assert.Equal(0, this.repositorySavesCount);

            // Dispose block store to trigger save.
            this.nodeLifetime.StopApplication();
            this.blockStoreQueue.Dispose();

            // Make sure that blocks only from 2nd chain were saved.
            Assert.Equal(this.chainIndexer.GetHeader(realChainLenght - 1), this.chainState.BlockStoreTip);
            Assert.Equal(1, this.repositorySavesCount);
            Assert.Equal(realChainLenght - 1, this.repositoryTotalBlocksSaved);
        }
        public async Task BatchIsSavedWhenAtConsensusTipAsync()
        {
            this.repositoryTipHashAndHeight = new HashHeightPair(this.chainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushConditionMock = new Mock <IBlockStoreQueueFlushCondition>();

            blockStoreFlushConditionMock.Setup(s => s.ShouldFlush).Returns(false);
            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushConditionMock.Object, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();
            this.chainState.ConsensusTip = this.chainIndexer.Tip;

            for (int i = 1; i <= this.chainIndexer.Height; i++)
            {
                ChainedHeader lastHeader = this.chainIndexer.GetHeader(i);
                Block         block      = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                if (i == this.chainIndexer.Height)
                {
                    await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

                    blockStoreFlushConditionMock.Setup(s => s.ShouldFlush).Returns(true);
                }

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, lastHeader));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            // Wait for store tip to finish saving
            int counter = 0;

            if (this.chainState.BlockStoreTip != this.chainIndexer.Tip)
            {
                Assert.True(counter < 10);
                counter++;
                await Task.Delay(500);
            }

            Assert.Equal(this.chainState.BlockStoreTip, this.chainIndexer.Tip);
            Assert.Equal(1, this.repositorySavesCount);
        }
        public async Task ReorgedBlocksAreDeletedFromRepositoryIfReorgDetectedAsync()
        {
            this.chainIndexer = CreateChain(1000);
            this.repositoryTipHashAndHeight = new HashHeightPair(this.chainIndexer.Genesis.HashBlock, 0);

            var blockStoreFlushCondition = new Mock <IBlockStoreQueueFlushCondition>();

            blockStoreFlushCondition.Setup(s => s.ShouldFlush).Returns(false);

            this.blockStoreQueue = new BlockStoreQueue(this.chainIndexer, this.chainState, blockStoreFlushCondition.Object, this.storeSettings,
                                                       this.blockRepositoryMock.Object, this.loggerFactory, new Mock <INodeStats>().Object, this.asyncProvider);

            this.blockStoreQueue.Initialize();
            this.chainState.ConsensusTip = this.chainIndexer.Tip;

            // Sending 500 blocks to the queue.
            for (int i = 1; i < 500; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, this.chainIndexer.GetHeader(i)));
            }

            // Create alternative chain with fork point at 450.
            ChainedHeader prevBlock         = this.chainIndexer.GetHeader(450);
            var           alternativeBlocks = new List <ChainedHeader>();

            for (int i = 0; i < 100; i++)
            {
                BlockHeader header = this.network.Consensus.ConsensusFactory.CreateBlockHeader();
                header.Nonce         = RandomUtils.GetUInt32();
                header.HashPrevBlock = prevBlock.HashBlock;
                header.Bits          = Target.Difficulty1;

                var chainedHeader = new ChainedHeader(header, header.GetHash(), prevBlock);
                alternativeBlocks.Add(chainedHeader);
                prevBlock = chainedHeader;
            }

            ChainedHeader savedHeader = this.chainIndexer.Tip;

            this.chainIndexer.SetTip(alternativeBlocks.Last());
            this.chainState.ConsensusTip = this.chainIndexer.Tip;

            // Present alternative chain and trigger save.
            foreach (ChainedHeader header in alternativeBlocks)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                if (header == alternativeBlocks.Last())
                {
                    blockStoreFlushCondition.Setup(s => s.ShouldFlush).Returns(true);
                }

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, header));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            blockStoreFlushCondition.Setup(s => s.ShouldFlush).Returns(false);

            // Make sure only longest chain is saved.
            Assert.Equal(this.chainIndexer.Tip.Height, this.repositoryTotalBlocksSaved);

            // Present a new longer chain that will reorg the repository.
            this.chainIndexer.SetTip(savedHeader);
            this.chainState.ConsensusTip = this.chainIndexer.Tip;

            for (int i = 451; i <= this.chainIndexer.Height; i++)
            {
                Block block = this.network.Consensus.ConsensusFactory.CreateBlock();
                block.GetSerializedSize();

                if (i == this.chainIndexer.Height)
                {
                    blockStoreFlushCondition.Setup(s => s.ShouldFlush).Returns(true);
                }

                this.blockStoreQueue.AddToPending(new ChainedHeaderBlock(block, this.chainIndexer.GetHeader(i)));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            // Make sure chain is saved.
            Assert.Equal(this.chainIndexer.Tip.Height + alternativeBlocks.Count, this.repositoryTotalBlocksSaved);
            Assert.Equal(alternativeBlocks.Count, this.repositoryTotalBlocksDeleted);

            // Dispose block store.
            this.nodeLifetime.StopApplication();
            this.blockStoreQueue.Dispose();
        }
Example #10
0
        /// <summary>
        /// Creates test chain with a consensus loop.
        /// </summary>
        public static async Task <TestChainContext> CreateAsync(Network network, string dataDir, Mock <IPeerAddressManager> mockPeerAddressManager = null)
        {
            var testChainContext = new TestChainContext()
            {
                Network = network
            };

            testChainContext.NodeSettings       = new NodeSettings(network, args: new string[] { $"-datadir={dataDir}" });
            testChainContext.ConnectionSettings = new ConnectionManagerSettings(testChainContext.NodeSettings);
            testChainContext.LoggerFactory      = testChainContext.NodeSettings.LoggerFactory;
            testChainContext.DateTimeProvider   = DateTimeProvider.Default;

            network.Consensus.Options = new ConsensusOptions();
            new FullNodeBuilderConsensusExtension.PowConsensusRulesRegistration().RegisterRules(network.Consensus);

            var consensusSettings = new ConsensusSettings(testChainContext.NodeSettings);

            testChainContext.Checkpoints = new Checkpoints();
            testChainContext.Chain       = new ConcurrentChain(network);
            testChainContext.ChainState  = new ChainState();
            testChainContext.InitialBlockDownloadState = new InitialBlockDownloadState(testChainContext.ChainState, testChainContext.Network, consensusSettings, new Checkpoints());

            var inMemoryCoinView = new InMemoryCoinView(testChainContext.Chain.Tip.HashBlock);
            var cachedCoinView   = new CachedCoinView(inMemoryCoinView, DateTimeProvider.Default, testChainContext.LoggerFactory);

            var dataFolder = new DataFolder(TestBase.AssureEmptyDir(dataDir));

            testChainContext.PeerAddressManager =
                mockPeerAddressManager == null ?
                new PeerAddressManager(DateTimeProvider.Default, dataFolder, testChainContext.LoggerFactory, new SelfEndpointTracker(testChainContext.LoggerFactory))
                    : mockPeerAddressManager.Object;

            testChainContext.MockConnectionManager       = new Mock <IConnectionManager>();
            testChainContext.MockReadOnlyNodesCollection = new Mock <IReadOnlyNetworkPeerCollection>();
            testChainContext.MockConnectionManager.Setup(s => s.ConnectedPeers).Returns(testChainContext.MockReadOnlyNodesCollection.Object);
            testChainContext.MockConnectionManager.Setup(s => s.NodeSettings).Returns(testChainContext.NodeSettings);
            testChainContext.MockConnectionManager.Setup(s => s.ConnectionSettings).Returns(testChainContext.ConnectionSettings);

            testChainContext.ConnectionManager = testChainContext.MockConnectionManager.Object;

            testChainContext.PeerBanning = new PeerBanning(testChainContext.ConnectionManager, testChainContext.LoggerFactory, testChainContext.DateTimeProvider, testChainContext.PeerAddressManager);
            var deployments = new NodeDeployments(testChainContext.Network, testChainContext.Chain);

            testChainContext.ConsensusRules = new PowConsensusRuleEngine(testChainContext.Network, testChainContext.LoggerFactory, testChainContext.DateTimeProvider,
                                                                         testChainContext.Chain, deployments, consensusSettings, testChainContext.Checkpoints, cachedCoinView, testChainContext.ChainState, new InvalidBlockHashStore(new DateTimeProvider()))
                                              .Register();

            testChainContext.HeaderValidator    = new HeaderValidator(testChainContext.ConsensusRules, testChainContext.LoggerFactory);
            testChainContext.IntegrityValidator = new IntegrityValidator(testChainContext.ConsensusRules, testChainContext.LoggerFactory);
            testChainContext.PartialValidator   = new PartialValidator(testChainContext.ConsensusRules, testChainContext.LoggerFactory);
            testChainContext.FullValidator      = new FullValidator(testChainContext.ConsensusRules, testChainContext.LoggerFactory);

            var blockRepository = new BlockRepository(testChainContext.Network, dataFolder, testChainContext.DateTimeProvider, testChainContext.LoggerFactory);
            var blockStore      = new BlockStoreQueue(testChainContext.Chain, testChainContext.ChainState, new Mock <StoreSettings>().Object,
                                                      new Mock <INodeLifetime>().Object, blockRepository, testChainContext.LoggerFactory, new Mock <INodeStats>().Object);

            await blockStore.InitializeAsync();

            testChainContext.Consensus = ConsensusManagerHelper.CreateConsensusManager(network, dataDir);

            await testChainContext.Consensus.InitializeAsync(testChainContext.Chain.Tip);

            return(testChainContext);
        }
Example #11
0
        public async Task ReorgedBlocksAreDeletedFromRepositoryIfReorgDetectedAsync()
        {
            this.chain = this.CreateChain(1000);
            this.repositoryBlockHash = this.chain.Genesis.HashBlock;

            this.blockStoreQueue = new BlockStoreQueue(this.repository, this.chain, this.chainState, new StoreSettings(), this.nodeLifetime, new LoggerFactory());

            await this.blockStoreQueue.InitializeAsync().ConfigureAwait(false);

            this.consensusTip = this.chain.Tip;

            // Sending 500 blocks to the queue.
            for (int i = 1; i < 500; i++)
            {
                Block block = new Block();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new BlockPair(block, this.chain.GetBlock(i)));
            }

            // Create alternative chain with fork point at 450.
            ChainedHeader prevBlock         = this.chain.GetBlock(450);
            var           alternativeBlocks = new List <ChainedHeader>();

            for (int i = 0; i < 100; i++)
            {
                var header = new BlockHeader()
                {
                    Nonce         = RandomUtils.GetUInt32(),
                    HashPrevBlock = prevBlock.HashBlock,
                    Bits          = Target.Difficulty1
                };

                var chainedHeader = new ChainedHeader(header, header.GetHash(), prevBlock);
                alternativeBlocks.Add(chainedHeader);
                prevBlock = chainedHeader;
            }

            ChainedHeader savedHeader = this.chain.Tip;

            this.chain.SetTip(alternativeBlocks.Last());
            this.consensusTip = this.chain.Tip;

            // Present alternative chain and trigger save.
            foreach (ChainedHeader header in alternativeBlocks)
            {
                Block block = new Block();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new BlockPair(block, header));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            // Make sure only longest chain is saved.
            Assert.Equal(1, this.repositorySavesCount);
            Assert.Equal(this.chain.Tip.Height, this.repositoryTotalBlocksSaved);

            // Present a new longer chain that will reorg the repository.
            this.chain.SetTip(savedHeader);
            this.consensusTip = this.chain.Tip;

            for (int i = 451; i <= this.chain.Height; i++)
            {
                Block block = new Block();
                block.GetSerializedSize();

                this.blockStoreQueue.AddToPending(new BlockPair(block, this.chain.GetBlock(i)));
            }

            await this.WaitUntilQueueIsEmptyAsync().ConfigureAwait(false);

            // Make sure chain is saved.
            Assert.Equal(2, this.repositorySavesCount);
            Assert.Equal(this.chain.Tip.Height + alternativeBlocks.Count, this.repositoryTotalBlocksSaved);
            Assert.Equal(alternativeBlocks.Count, this.repositoryTotalBlocksDeleted);

            // Dispose block store.
            this.nodeLifetime.StopApplication();
            this.blockStoreQueue.Dispose();
        }
Example #12
0
 public BlockStoreManager(IBlockRepository blockRepository, BlockStoreQueue blockStoreQueue)
 {
     this.BlockRepository = blockRepository;
     this.BlockStoreQueue = blockStoreQueue;
 }