Example #1
0
        public void When_deleting_invalid_block_deletes_its_descendants()
        {
            MemDb     blocksDb     = new MemDb();
            MemDb     blockInfosDb = new MemDb();
            BlockTree tree         = new BlockTree(blocksDb, blockInfosDb, MainNetSpecProvider.Instance, NullTransactionPool.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;

            tree.SuggestBlock(block0);
            tree.SuggestBlock(block1);
            tree.SuggestBlock(block2);
            tree.SuggestBlock(block3);

            tree.UpdateMainChain(block0);
            tree.UpdateMainChain(block1);
            tree.DeleteInvalidBlock(block2);

            Assert.AreEqual(UInt256.One, tree.BestKnownNumber, "best known");
            Assert.AreEqual(UInt256.One, tree.Head.Number, "head");
            Assert.AreEqual(UInt256.One, tree.BestSuggested.Number, "suggested");

            Assert.NotNull(blocksDb.Get(block1.Hash), "block 1");
            Assert.IsNull(blocksDb.Get(block2.Hash), "block 2");
            Assert.IsNull(blocksDb.Get(block3.Hash), "block 3");

            Assert.NotNull(blockInfosDb.Get(1), "level 1");
            Assert.IsNull(blockInfosDb.Get(2), "level 2");
            Assert.IsNull(blockInfosDb.Get(3), "level 3");
        }
Example #2
0
        public async Task Can_load_from_DB_when_there_is_only_an_invalid_chain_in_DB()
        {
            MemDb     blocksDb     = new MemDb();
            MemDb     blockInfosDb = new MemDb();
            MemDb     headersDb    = new MemDb();
            BlockTree tree1        = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.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;

            tree1.SuggestBlock(block0);
            tree1.SuggestBlock(block1);
            tree1.SuggestBlock(block2);
            tree1.SuggestBlock(block3);

            tree1.UpdateMainChain(block0);

            BlockTree tree2 = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.Instance, NullBloomStorage.Instance, LimboLogs.Instance);

            CancellationTokenSource tokenSource = new CancellationTokenSource();

#pragma warning disable 4014
            Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel());
#pragma warning restore 4014

            tree2.NewBestSuggestedBlock += (sender, args) =>
            {
                if (args.Block.Hash == block1.Hash)
                {
                    tree2.DeleteInvalidBlock(args.Block);
                }
                else
                {
                    tree2.UpdateMainChain(args.Block);
                }
            };

            DbBlocksLoader loader = new DbBlocksLoader(tree2, LimboNoErrorLogger.Instance, null, 1);
            await tree2.Accept(loader, tokenSource.Token);

            /* note the block tree historically loads one less block than it could */

            Assert.AreEqual(0L, tree2.BestKnownNumber, "best known");
            Assert.AreEqual(block0.Hash, tree2.Head.Hash, "head");
            Assert.AreEqual(block0.Hash, tree2.BestSuggestedHeader.Hash, "suggested");

            Assert.IsNull(blocksDb.Get(block1.Hash), "block 1");
            Assert.IsNull(blocksDb.Get(block2.Hash), "block 2");
            Assert.IsNull(blocksDb.Get(block3.Hash), "block 3");

            Assert.IsNull(blockInfosDb.Get(1), "level 1");
            Assert.IsNull(blockInfosDb.Get(2), "level 2");
            Assert.IsNull(blockInfosDb.Get(3), "level 3");
        }
Example #3
0
        public async Task Can_load_from_DB_when_there_is_only_an_invalid_chain_in_DB()
        {
            MemDb     blocksDb     = new MemDb();
            MemDb     blockInfosDb = new MemDb();
            BlockTree tree1        = new BlockTree(blocksDb, blockInfosDb, MainNetSpecProvider.Instance, NullTransactionPool.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;

            tree1.SuggestBlock(block0);
            tree1.SuggestBlock(block1);
            tree1.SuggestBlock(block2);
            tree1.SuggestBlock(block3);

            tree1.UpdateMainChain(block0);

            BlockTree tree2 = new BlockTree(blocksDb, blockInfosDb, MainNetSpecProvider.Instance, NullTransactionPool.Instance, LimboLogs.Instance);

            CancellationTokenSource tokenSource = new CancellationTokenSource();

#pragma warning disable 4014
            Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel());
#pragma warning restore 4014

            tree2.NewBestSuggestedBlock += (sender, args) =>
            {
                if (args.Block.Hash == block1.Hash)
                {
                    tree2.DeleteInvalidBlock(args.Block);
                }
                else
                {
                    tree2.UpdateMainChain(args.Block);
                }
            };

            await tree2.LoadBlocksFromDb(tokenSource.Token, startBlockNumber : null, batchSize : 1);

            /* note the block tree historically loads one less block than it could */

            Assert.AreEqual((UInt256)0, tree2.BestKnownNumber, "best known");
            Assert.AreEqual(block0.Hash, tree2.Head.Hash, "head");
            Assert.AreEqual(block0.Hash, tree2.BestSuggested.Hash, "suggested");

            Assert.IsNull(blocksDb.Get(block1.Hash), "block 1");
            Assert.IsNull(blocksDb.Get(block2.Hash), "block 2");
            Assert.IsNull(blocksDb.Get(block3.Hash), "block 3");

            Assert.IsNull(blockInfosDb.Get(1), "level 1");
            Assert.IsNull(blockInfosDb.Get(2), "level 2");
            Assert.IsNull(blockInfosDb.Get(3), "level 3");
        }
Example #4
0
        public void After_removing_invalid_block_will_not_accept_it_again()
        {
            MemDb     blocksDb     = new MemDb();
            MemDb     blockInfosDb = new MemDb();
            BlockTree tree         = new BlockTree(blocksDb, blockInfosDb, MainNetSpecProvider.Instance, NullTransactionPool.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;

            tree.SuggestBlock(block0);
            tree.SuggestBlock(block1);
            tree.SuggestBlock(block2);
            tree.SuggestBlock(block3);

            tree.DeleteInvalidBlock(block1);
            AddBlockResult result = tree.SuggestBlock(block1);

            Assert.AreEqual(AddBlockResult.InvalidBlock, result);
        }
Example #5
0
        public void When_deleting_invalid_block_sets_head_bestKnown_and_suggested_right()
        {
            BlockTree tree   = BuildBlockTree();
            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;

            tree.SuggestBlock(block0);
            tree.SuggestBlock(block1);
            tree.SuggestBlock(block2);
            tree.SuggestBlock(block3);

            tree.UpdateMainChain(block0);
            tree.UpdateMainChain(block1);
            tree.DeleteInvalidBlock(block2);

            Assert.AreEqual(block1.Number, tree.BestKnownNumber);
            Assert.AreEqual(block1.Header, tree.Head);
            Assert.AreEqual(block1.Header, tree.BestSuggested);
        }
Example #6
0
        public async Task Can_load_from_DB_when_there_is_an_invalid_block_in_DB_and_a_valid_branch()
        {
            MemDb     blocksDb     = new MemDb();
            MemDb     blockInfosDb = new MemDb();
            MemDb     headersDb    = new MemDb();
            BlockTree tree1        = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.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 block1B = Build.A.Block.WithNumber(1).WithDifficulty(1).WithParent(block0).TestObject;
            Block block2B = Build.A.Block.WithNumber(2).WithDifficulty(1).WithParent(block1B).TestObject;
            Block block3B = Build.A.Block.WithNumber(3).WithDifficulty(1).WithParent(block2B).TestObject;

            tree1.SuggestBlock(block0);
            tree1.SuggestBlock(block1); // invalid block
            tree1.SuggestBlock(block2); // invalid branch
            tree1.SuggestBlock(block3); // invalid branch

            tree1.SuggestBlock(block1B);
            tree1.SuggestBlock(block2B);
            tree1.SuggestBlock(block3B); // expected to be head

            tree1.UpdateMainChain(block0);

            BlockTree tree2 = new BlockTree(blocksDb, headersDb, blockInfosDb, new ChainLevelInfoRepository(blockInfosDb), MainnetSpecProvider.Instance, NullTxPool.Instance, NullBloomStorage.Instance, LimboLogs.Instance);

            CancellationTokenSource tokenSource = new CancellationTokenSource();

#pragma warning disable 4014
            Task.Delay(_dbLoadTimeout).ContinueWith(t => tokenSource.Cancel());
#pragma warning restore 4014

            tree2.NewBestSuggestedBlock += (sender, args) =>
            {
                if (args.Block.Hash == block1.Hash)
                {
                    tree2.DeleteInvalidBlock(args.Block);
                }
                else
                {
                    tree2.UpdateMainChain(args.Block);
                }
            };

            DbBlocksLoader loader = new DbBlocksLoader(tree2, LimboNoErrorLogger.Instance, null, 1);
            await tree2.Accept(loader, tokenSource.Token);

            Assert.AreEqual(3L, tree2.BestKnownNumber, "best known");
            tree2.Head.Header.Should().BeEquivalentTo(block3B.Header, options => { return(options.Excluding(t => t.MaybeParent)); });
            tree2.BestSuggestedHeader.Should().BeEquivalentTo(block3B.Header, options => { return(options.Excluding(t => t.MaybeParent)); });

            Assert.IsNull(blocksDb.Get(block1.Hash), "block 1");
            Assert.IsNull(blocksDb.Get(block2.Hash), "block 2");
            Assert.IsNull(blocksDb.Get(block3.Hash), "block 3");

            Assert.NotNull(blockInfosDb.Get(1), "level 1");
            Assert.NotNull(blockInfosDb.Get(2), "level 2");
            Assert.NotNull(blockInfosDb.Get(3), "level 3");
        }