/// <summary> /// Mock a chain with a best branch, and some fork branches /// </summary> /// <returns> /// Mock Chain /// BestChainHeight: 11 /// LongestChainHeight: 13 /// LIB height: 5 /// /// Height: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 /// Best Branch: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k /// Longest Branch: (h)-> l -> m -> n -> o -> p /// Fork Branch: (e)-> q -> r -> s -> t -> u /// Unlinked Branch: v -> w -> x -> y -> z /// </returns> public async Task <Chain> MockChainAsync() { var chain = await CreateChain(); var genesisBlock = await _blockchainService.GetBlockByHashAsync(chain.GenesisBlockHash); BestBranchBlockList.Add(genesisBlock); BestBranchBlockList.AddRange(await AddBestBranch(chain)); LongestBranchBlockList = await AddForkBranch(chain, BestBranchBlockList[7].Height, BestBranchBlockList[7].GetHash()); foreach (var block in LongestBranchBlockList) { var chainBlockLink = await _chainManager.GetChainBlockLinkAsync(block.GetHash()); await _chainManager.SetChainBlockLinkExecutionStatus(chainBlockLink, ChainBlockLinkExecutionStatus.ExecutionFailed); } ForkBranchBlockList = await AddForkBranch(chain, BestBranchBlockList[4].Height, BestBranchBlockList[4].GetHash()); UnlinkedBranchBlockList = await AddForkBranch(chain, 9, Hash.FromString("UnlinkBlock")); // Set lib chain = await _blockchainService.GetChainAsync(); await _blockchainService.SetIrreversibleBlockAsync(chain, BestBranchBlockList[4].Height, BestBranchBlockList[4].GetHash()); return(chain); }
public async Task Set_IrreversibleBlock_Concurrence() { var chain = await _fullBlockchainService.GetChainAsync(); // LIB height: 8 // // Height: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 // Best Branch: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k // Longest Branch: (h)-> l -> m -> n -> o -> p // Fork Branch: (e)-> q -> r -> s -> t -> u // Unlinked Branch: ae v -> w -> x -> y -> z await _fullBlockchainService.SetIrreversibleBlockAsync(chain, _kernelTestHelper.BestBranchBlockList[7] .Height, _kernelTestHelper.BestBranchBlockList[7].GetHash()); var newUnlinkedBlock = _kernelTestHelper.GenerateBlock(7, Hash.FromString("NewUnlinked"), new List <Transaction> { _kernelTestHelper.GenerateTransaction() }); await _fullBlockchainService.AddBlockAsync(newUnlinkedBlock); await _fullBlockchainService.AttachBlockToChainAsync(chain, newUnlinkedBlock); var previousBlockHeight = _kernelTestHelper.BestBranchBlockList.Last().Height; var previousBlockHash = _kernelTestHelper.BestBranchBlockList.Last().GetHash(); // Miner mined one block var minerAttachBlock = await _kernelTestHelper.AttachBlock(previousBlockHeight, previousBlockHash); chain = await _fullBlockchainService.GetChainAsync(); await _fullBlockchainService.SetBestChainAsync(chain, minerAttachBlock.Height, minerAttachBlock.GetHash()); var chainBlockLink = await _chainManager.GetChainBlockLinkAsync(minerAttachBlock.GetHash()); await _chainManager.SetChainBlockLinkExecutionStatus(chainBlockLink, ChainBlockLinkExecutionStatus.ExecutionSuccess); var minerAttachChain = await _fullBlockchainService.GetChainAsync(); // Network sync two blocks Block syncAttachBlock = null; for (var i = 0; i < 2; i++) { syncAttachBlock = await _kernelTestHelper.AttachBlock(previousBlockHeight, previousBlockHash); chain = await _fullBlockchainService.GetChainAsync(); await _fullBlockchainService.SetBestChainAsync(chain, syncAttachBlock.Height, syncAttachBlock.GetHash()); chainBlockLink = await _chainManager.GetChainBlockLinkAsync(syncAttachBlock.GetHash()); await _chainManager.SetChainBlockLinkExecutionStatus(chainBlockLink, ChainBlockLinkExecutionStatus.ExecutionSuccess); previousBlockHeight = syncAttachBlock.Height; previousBlockHash = syncAttachBlock.GetHash(); } var syncAttachChain = await _fullBlockchainService.GetChainAsync(); { // LIB height: 9 // // Height: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 // Best Branch: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k // Longest Branch: (-) (h)-> l -> m -> n -> o -> p // Fork Branch: (-) (e)-> q -> r -> s -> t -> u // Unlinked Branch: ae(-) v -> w -> x -> y -> z // Miner Branch: (k) -> aa //Network Sync Branch: (k) -> ab -> ac syncAttachChain.NotLinkedBlocks.Count.ShouldBe(6); BlocksShouldExist(new List <Hash> { newUnlinkedBlock.GetHash() }); await _fullBlockchainService.SetIrreversibleBlockAsync(syncAttachChain, _kernelTestHelper .BestBranchBlockList[8].Height, _kernelTestHelper.BestBranchBlockList[8].GetHash()); chain = await _fullBlockchainService.GetChainAsync(); chain.LastIrreversibleBlockHash.ShouldBe(_kernelTestHelper.BestBranchBlockList[8].GetHash()); chain.LastIrreversibleBlockHeight.ShouldBe(_kernelTestHelper.BestBranchBlockList[8].Height); chain.Branches.Count.ShouldBe(3); chain.NotLinkedBlocks.Count.ShouldBe(5); BlocksShouldNotExist(_kernelTestHelper.ForkBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.BestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.LongestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.UnlinkedBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldNotExist(new List <Hash> { newUnlinkedBlock.GetHash() }); } { // LIB height: 10 // // Height: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 // Best Branch: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k // Longest Branch: (-) (h)-> l -> m -> n -> o -> p // Fork Branch: (-) (e)-> q -> r -> s -> t -> u -> ad // Unlinked Branch: ae(-) v -> w -> x -> y -> z // Miner Branch: (k) -> aa //Network Sync Branch: (-) (k) -> ab -> ac var newBlock = _kernelTestHelper.GenerateBlock(_kernelTestHelper.ForkBranchBlockList.Last().Height, _kernelTestHelper.ForkBranchBlockList.Last().GetHash(), new List <Transaction> { _kernelTestHelper.GenerateTransaction() }); await _fullBlockchainService.AddBlockAsync(newBlock); await _fullBlockchainService.AttachBlockToChainAsync(minerAttachChain, newBlock); minerAttachChain.Branches.Count.ShouldBe(3); await _fullBlockchainService.SetIrreversibleBlockAsync(minerAttachChain, _kernelTestHelper .BestBranchBlockList[9].Height, _kernelTestHelper.BestBranchBlockList[9].GetHash()); chain = await _fullBlockchainService.GetChainAsync(); chain.LastIrreversibleBlockHeight.ShouldBe(_kernelTestHelper.BestBranchBlockList[9].Height); chain.LastIrreversibleBlockHash.ShouldBe(_kernelTestHelper.BestBranchBlockList[9].GetHash()); chain.Branches.Count.ShouldBe(2); chain.NotLinkedBlocks.Count.ShouldBe(5); BlocksShouldNotExist(_kernelTestHelper.ForkBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.BestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.LongestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.UnlinkedBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldNotExist(new List <Hash> { newBlock.GetHash() }); } { // LIB height: 11 // // Height: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13 -> 14 // Best Branch: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k // Longest Branch: (-) (h)-> l -> m -> n -> o -> p // Fork Branch: (-) (e)-> q -> r -> s -> t -> u // Unlinked Branch: ae(-) v(-)-> w -> x -> y -> z // Miner Branch: (k) -> aa //Network Sync Branch: (-) (k) -> ab -> ac await _fullBlockchainService.SetIrreversibleBlockAsync(chain, _kernelTestHelper .BestBranchBlockList[10].Height, _kernelTestHelper.BestBranchBlockList[10].GetHash()); chain = await _fullBlockchainService.GetChainAsync(); chain.LastIrreversibleBlockHeight.ShouldBe(_kernelTestHelper.BestBranchBlockList[10].Height); chain.LastIrreversibleBlockHash.ShouldBe(_kernelTestHelper.BestBranchBlockList[10].GetHash()); chain.LongestChainHash.ShouldBe(minerAttachBlock.GetHash()); chain.LongestChainHeight.ShouldBe(minerAttachBlock.Height); chain.Branches.Count.ShouldBe(1); chain.NotLinkedBlocks.Count.ShouldBe(4); BlocksShouldNotExist(_kernelTestHelper.ForkBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldExist(_kernelTestHelper.BestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldNotExist(_kernelTestHelper.LongestBranchBlockList.Select(b => b.GetHash()).ToList()); BlocksShouldNotExist(new List <Hash> { _kernelTestHelper.UnlinkedBranchBlockList[0].GetHash() }); BlocksShouldExist(new List <Hash> { _kernelTestHelper.UnlinkedBranchBlockList[1].GetHash(), _kernelTestHelper.UnlinkedBranchBlockList[2].GetHash(), _kernelTestHelper.UnlinkedBranchBlockList[3].GetHash(), _kernelTestHelper.UnlinkedBranchBlockList[4].GetHash() }); } }
public async Task <List <ChainBlockLink> > ExecuteBlocksAttachedToLongestChain(Chain chain, BlockAttachOperationStatus status) { if (!status.HasFlag(BlockAttachOperationStatus.LongestChainFound)) { Logger.LogTrace($"Try to attach to chain but the status is {status}."); return(null); } var successLinks = new List <ChainBlockLink>(); var blockLinks = await _chainManager.GetNotExecutedBlocks(chain.LongestChainHash); try { foreach (var blockLink in blockLinks) { var linkedBlock = await _blockchainService.GetBlockByHashAsync(blockLink.BlockHash); // Set the other blocks as bad block if found the first bad block if (!await _blockValidationService.ValidateBlockBeforeExecuteAsync(linkedBlock)) { await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionFailed); Logger.LogWarning($"Block validate fails before execution. block hash : {blockLink.BlockHash}"); break; } if (!await ExecuteBlock(blockLink, linkedBlock)) { await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionFailed); Logger.LogWarning($"Block execution failed. block hash : {blockLink.BlockHash}"); break; } if (!await _blockValidationService.ValidateBlockAfterExecuteAsync(linkedBlock)) { await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionFailed); Logger.LogWarning($"Block validate fails after execution. block hash : {blockLink.BlockHash}"); break; } await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionSuccess); successLinks.Add(blockLink); Logger.LogInformation($"Executed block {blockLink.BlockHash} at height {blockLink.Height}."); await LocalEventBus.PublishAsync(new BlockAcceptedEvent() { BlockHeader = linkedBlock.Header }); } } catch (ValidateNextTimeBlockValidationException ex) { Logger.LogWarning($"Block validate fails after execution. Exception message {ex.Message}"); } if (successLinks.Count > 0) { var blockLink = successLinks.Last(); await _blockchainService.SetBestChainAsync(chain, blockLink.Height, blockLink.BlockHash); await LocalEventBus.PublishAsync(new BestChainFoundEventData { BlockHash = chain.BestChainHash, BlockHeight = chain.BestChainHeight, ExecutedBlocks = successLinks.Select(p => p.BlockHash).ToList() }); } Logger.LogInformation($"Attach blocks to best chain, status: {status}, best chain hash: {chain.BestChainHash}, height: {chain.BestChainHeight}"); return(blockLinks); }
public async Task <List <ChainBlockLink> > ExecuteBlocksAttachedToLongestChain(Chain chain, BlockAttachOperationStatus status) { if (!status.HasFlag(BlockAttachOperationStatus.LongestChainFound)) { Logger.LogTrace($"Try to attach to chain but the status is {status}."); return(null); } var successLinks = new List <ChainBlockLink>(); var blockLinks = await _chainManager.GetNotExecutedBlocks(chain.LongestChainHash); try { foreach (var blockLink in blockLinks) { var linkedBlock = await _blockchainService.GetBlockByHashAsync(blockLink.BlockHash); var processResult = await TryProcessBlockAsync(linkedBlock); if (!processResult) { await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionFailed); await _chainManager.RemoveLongestBranchAsync(chain); return(null); } successLinks.Add(blockLink); Logger.LogInformation($"Executed block {blockLink.BlockHash} at height {blockLink.Height}."); await LocalEventBus.PublishAsync(new BlockAcceptedEvent() { BlockHeader = linkedBlock.Header }); } } catch (BlockValidationException ex) { if (!(ex.InnerException is ValidateNextTimeBlockValidationException)) { await _chainManager.RemoveLongestBranchAsync(chain); throw; } Logger.LogWarning( $"Block validation failed: {ex.Message}. Inner exception {ex.InnerException.Message}"); } catch (Exception ex) { await _chainManager.RemoveLongestBranchAsync(chain); Logger.LogWarning($"Block validate or execute fails. Exception message {ex.Message}"); throw; } if (successLinks.Count == 0) { Logger.LogWarning("No block execution succeed in this branch."); await _chainManager.RemoveLongestBranchAsync(chain); return(null); } await SetBestChainAsync(successLinks, chain); foreach (var blockLink in successLinks) { await _chainManager.SetChainBlockLinkExecutionStatus(blockLink, ChainBlockLinkExecutionStatus.ExecutionSuccess); } Logger.LogInformation( $"Attach blocks to best chain, status: {status}, best chain hash: {chain.BestChainHash}, height: {chain.BestChainHeight}"); return(blockLinks); }