public async void should_request_previous_block_if_missing() { //arrange var block = BuildBlock(); GivenVerificationPasses(block); A.CallTo(() => _blockRepository.GetBlockHeader(block.Header.PreviousBlock)) .Returns(Task.FromResult <BlockHeader>(null)); A.CallTo(() => _blockRepository.GetBestBlockHeader()) .Returns(Task.FromResult <BlockHeader>(null)); A.CallTo(() => _blockRepository.IsEmpty()) .Returns(false); //act var result = await _subject.RecieveBlock(block); //assert A.CallTo(() => _peerNetwork.RequestBlock(block.Header.PreviousBlock)) .MustHaveHappened(); A.CallTo(() => _blockRepository.AddBlock(block)) .MustNotHaveHappened(); }
private async Task <PeerDataResult> RecieveBlockUnprotected(Block block) { var isTip = false; _logger.LogInformation($"Recv block {block.Header.Height} {BitConverter.ToString(block.Header.BlockId)}"); if (await _blockRepository.HavePrimaryBlock(block.Header.BlockId)) { _logger.LogInformation("already have block"); return(PeerDataResult.Ignore); } if (!await _blockVerifier.Verify(block)) { _logger.LogWarning($"Block verification failed for {BitConverter.ToString(block.Header.BlockId)}"); return(PeerDataResult.Demerit); } if (!await _blockVerifier.VerifyBlockRules(block, true)) { _logger.LogWarning($"Block rules failed for {BitConverter.ToString(block.Header.BlockId)}"); return(PeerDataResult.Demerit); } var prevHeader = await _blockRepository.GetBlockHeader(block.Header.PreviousBlock); var bestHeader = await _blockRepository.GetBestBlockHeader(); var isEmpty = await _blockRepository.IsEmpty(); bool mainChain = false; bool rebaseChain = false; isTip = (block.Header.PreviousBlock.SequenceEqual(bestHeader?.BlockId ?? Block.HeadKey)); _logger.LogInformation($"Is Tip {isTip}"); if (prevHeader != null) { _logger.LogInformation("Do Have previous block"); if (block.Header.Timestamp < prevHeader.Timestamp) { _logger.LogInformation("Timestamps dont match"); return(PeerDataResult.Ignore); } if (block.Header.Height != (prevHeader.Height + 1)) { _logger.LogInformation($"Height mismatch prev: {prevHeader.Height}, this: {block.Header.Height}"); return(PeerDataResult.Ignore); } if (!isTip) { var prevMain = await _blockRepository.GetPrimaryHeader(block.Header.Height - 1); var isPrevOnMainChain = prevMain?.BlockId.SequenceEqual(block.Header.PreviousBlock) ?? false; var mainExisiting = await _blockRepository.GetPrimaryHeader(block.Header.Height); mainChain = ((mainExisiting == null) && (isPrevOnMainChain)); } else { mainChain = true; } rebaseChain = ((block.Header.Height > bestHeader.Height) && !mainChain); _logger.LogInformation($"Processing block, have prev, main chain: {mainChain}, rebase: {rebaseChain}"); var expectedDifficulty = await _difficultyCalculator.CalculateDifficulty(prevHeader.Timestamp); if ((mainChain) && (block.Header.Difficulty < expectedDifficulty)) { _logger.LogInformation("Difficulty mismatch"); return(PeerDataResult.Ignore); } } else { _logger.LogInformation("Dont have prev block"); if (isEmpty && !block.Header.PreviousBlock.SequenceEqual(Block.HeadKey)) { _logger.LogInformation("not first block but am empty"); return(PeerDataResult.Ignore); } mainChain = isEmpty; _logger.LogInformation($"Processing block, missing prev, main chain: {mainChain}, rebase: {rebaseChain}"); _peerNetwork.RequestBlock(block.Header.PreviousBlock); } if (mainChain) { _logger.LogInformation("processing for main chain"); if (!await _blockVerifier.VerifyTransactions(block)) { _logger.LogWarning($"Block txn verification failed for {BitConverter.ToString(block.Header.BlockId)}"); return(PeerDataResult.Demerit); } await _blockRepository.AddBlock(block); _unconfirmedTransactionPool.Remove(block.Transactions); } else { if (!await _blockRepository.HaveSecondaryBlock(block.Header.BlockId)) { _logger.LogInformation($"Adding detached block"); await _blockRepository.AddSecondaryBlock(block); } if (rebaseChain) { _logger.LogInformation($"Searching for divergent block"); var divergentHeader = await _blockRepository.GetDivergentHeader(block.Header.BlockId); if (divergentHeader != null) { _logger.LogInformation($"Rebasing chain from {divergentHeader.Height}"); var replayBlocks = await _forkRebaser.RebaseChain(divergentHeader.BlockId, block.Header.BlockId); _logger.LogInformation($"Replaying {replayBlocks.Count} blocks"); foreach (var replayBlock in replayBlocks) { var replayResult = await RecieveBlockUnprotected(replayBlock); if (replayResult == PeerDataResult.Demerit) { break; } } _logger.LogInformation($"Replay complete"); } else { _logger.LogInformation($"Divergent block not found"); var firstForkHeader = await _forkRebaser.FindKnownForkbase(block.Header.BlockId); if (firstForkHeader != null) { _peerNetwork.RequestBlock(firstForkHeader.PreviousBlock); } } } } if (isTip) { _logger.LogDebug($"Accepted tip block {BitConverter.ToString(block.Header.BlockId)}"); return(PeerDataResult.Relay); } else { _logger.LogDebug($"Accepted block {BitConverter.ToString(block.Header.BlockId)}"); return(PeerDataResult.Ignore); } }