public void When_head_block_is_followed_by_a_block_bodies_gap_it_should_delete_all_levels_after_the_gap_start() { MemDb blocksDb = new MemDb(); MemDb blockInfosDb = new MemDb(); MemDb headersDb = new MemDb(); BlockTree tree = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; tree.SuggestBlock(block0); tree.SuggestBlock(block1); tree.SuggestBlock(block2); tree.SuggestHeader(block3.Header); tree.SuggestHeader(block4.Header); tree.SuggestBlock(block5); tree.UpdateMainChain(block2); StartupBlockTreeFixer fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, LimboNoErrorLogger.Instance); tree.Accept(fixer, CancellationToken.None); Assert.Null(blockInfosDb.Get(3), "level 3"); Assert.Null(blockInfosDb.Get(4), "level 4"); Assert.Null(blockInfosDb.Get(5), "level 5"); Assert.AreEqual(2L, tree.BestKnownNumber, "best known"); Assert.AreEqual(block2.Header, tree.Head?.Header, "head"); Assert.AreEqual(block2.Hash, tree.BestSuggestedHeader.Hash, "suggested"); }
public async Task Suggesting_blocks_works_correctly_after_processor_restart(int suggestedBlocksAmount) { TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); await testRpc.BlockchainProcessor.StopAsync(); IBlockTree tree = testRpc.BlockTree; long startingBlockNumber = tree.Head !.Number; SuggestNumberOfBlocks(tree, suggestedBlocksAmount); // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new BlockchainProcessor(tree, testRpc.BlockProcessor, testRpc.BlockPreprocessorStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; // fixing after restart StartupBlockTreeFixer fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, testRpc.DbProvider.StateDb, LimboNoErrorLogger.Instance, 5); await tree.Accept(fixer, CancellationToken.None); // waiting for N new heads for (int i = 0; i < suggestedBlocksAmount; ++i) { await testRpc.WaitForNewHead(); } // add a new block at the end await testRpc.AddBlock(); Assert.AreEqual(startingBlockNumber + suggestedBlocksAmount + 1, tree.Head !.Number); }
private async Task RunBlockTreeInitTasks() { ISyncConfig syncConfig = _context.Config <ISyncConfig>(); if (!syncConfig.SynchronizationEnabled) { return; } if (_context.BlockTree == null) { throw new StepDependencyException(nameof(_context.BlockTree)); } if (!syncConfig.FastSync && !syncConfig.BeamSync) { DbBlocksLoader loader = new DbBlocksLoader(_context.BlockTree, _logger); await _context.BlockTree.Accept(loader, _context.RunnerCancellation?.Token ?? CancellationToken.None).ContinueWith(t => { if (t.IsFaulted) { if (_logger.IsError) { _logger.Error("Loading blocks from the DB failed.", t.Exception); } } else if (t.IsCanceled) { if (_logger.IsWarn) { _logger.Warn("Loading blocks from the DB canceled."); } } }); } else { StartupBlockTreeFixer fixer = new StartupBlockTreeFixer(_context.Config <ISyncConfig>(), _context.BlockTree, _logger); await _context.BlockTree.Accept(fixer, _context.RunnerCancellation?.Token ?? CancellationToken.None).ContinueWith(t => { if (t.IsFaulted) { if (_logger.IsError) { _logger.Error("Fixing gaps in DB failed.", t.Exception); } } else if (t.IsCanceled) { if (_logger.IsWarn) { _logger.Warn("Fixing gaps in DB canceled."); } } }); } }
public void Deletes_everything_after_the_missing_level() { MemDb blocksDb = new MemDb(); MemDb blockInfosDb = new MemDb(); MemDb headersDb = new MemDb(); BlockTree tree = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); Block block0 = Build.A.Block.WithNumber(0).WithDifficulty(1).TestObject; Block block1 = Build.A.Block.WithNumber(1).WithDifficulty(2).WithParent(block0).TestObject; Block block2 = Build.A.Block.WithNumber(2).WithDifficulty(3).WithParent(block1).TestObject; Block block3 = Build.A.Block.WithNumber(3).WithDifficulty(4).WithParent(block2).TestObject; Block block4 = Build.A.Block.WithNumber(4).WithDifficulty(5).WithParent(block3).TestObject; Block block5 = Build.A.Block.WithNumber(5).WithDifficulty(6).WithParent(block4).TestObject; tree.SuggestBlock(block0); tree.SuggestBlock(block1); tree.SuggestBlock(block2); tree.SuggestBlock(block3); tree.SuggestBlock(block4); tree.SuggestHeader(block5.Header); tree.UpdateMainChain(block0); tree.UpdateMainChain(block1); tree.UpdateMainChain(block2); blockInfosDb.Delete(3); tree = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); StartupBlockTreeFixer fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, LimboNoErrorLogger.Instance); tree.Accept(fixer, CancellationToken.None); Assert.Null(blockInfosDb.Get(3), "level 3"); Assert.Null(blockInfosDb.Get(4), "level 4"); Assert.Null(blockInfosDb.Get(5), "level 5"); tree.Head.Header.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); tree.BestSuggestedHeader.Should().BeEquivalentTo(block2.Header, options => options.Excluding(t => t.MaybeParent)); tree.BestSuggestedBody.Should().BeEquivalentTo(block2.Body); tree.BestKnownNumber.Should().Be(2); }
public async Task Fixer_should_not_suggest_block_with_null_block() { TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); await testRpc.BlockchainProcessor.StopAsync(); IBlockTree tree = testRpc.BlockTree; SuggestNumberOfBlocks(tree, 1); // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, testRpc.BlockPreprocessorStep, testRpc.StateReader, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, testRpc.DbProvider.StateDb, LimboNoErrorLogger.Instance, 5); BlockVisitOutcome result = await fixer.VisitBlock(null, CancellationToken.None); Assert.AreEqual(BlockVisitOutcome.None, result); }
public async Task Fixer_should_not_suggest_block_without_state(int suggestedBlocksAmount) { TestRpcBlockchain testRpc = await TestRpcBlockchain.ForTest(SealEngineType.NethDev).Build(); await testRpc.BlockchainProcessor.StopAsync(); IBlockTree tree = testRpc.BlockTree; SuggestNumberOfBlocks(tree, suggestedBlocksAmount); // simulating restarts - we stopped the old blockchain processor and create the new one BlockchainProcessor newBlockchainProcessor = new(tree, testRpc.BlockProcessor, testRpc.BlockPreprocessorStep, LimboLogs.Instance, BlockchainProcessor.Options.Default); newBlockchainProcessor.Start(); testRpc.BlockchainProcessor = newBlockchainProcessor; // we create a new empty db for stateDb so we shouldn't suggest new blocks MemDb stateDb = new(); IBlockTreeVisitor fixer = new StartupBlockTreeFixer(new SyncConfig(), tree, stateDb, LimboNoErrorLogger.Instance, 5); BlockVisitOutcome result = await fixer.VisitBlock(tree.Head !, CancellationToken.None); Assert.AreEqual(BlockVisitOutcome.None, result); }