예제 #1
0
        /// <summary>
        /// Download and attach blocks
        /// UseSuggestedPeer == true: Download blocks from suggested peer directly;
        /// Target download height > peer lib height, download blocks from suggested peer;
        /// Target download height <= peer lib height, select a random peer to download.
        /// </summary>
        /// <param name="downloadBlockDto"></param>
        /// <returns></returns>
        public async Task <DownloadBlocksResult> DownloadBlocksAsync(DownloadBlockDto downloadBlockDto)
        {
            var downloadResult = new DownloadBlocksResult();
            var peerPubkey     = downloadBlockDto.SuggestedPeerPubkey;

            try
            {
                if (UseSuggestedPeer(downloadBlockDto))
                {
                    downloadResult = await DownloadBlocksAsync(peerPubkey, downloadBlockDto);
                }
                else
                {
                    // If cannot get the blocks, there should be network problems or bad peer,
                    // because we have selected peer with lib height greater than or equal to the target height.
                    // 1. network problems, need to retry from other peer.
                    // 2. not network problems, this peer or the last peer is bad peer, we need to remove it.
                    var downloadTargetHeight =
                        downloadBlockDto.PreviousBlockHeight + downloadBlockDto.MaxBlockDownloadCount;
                    var exceptedPeers = new List <string> {
                        _blockSyncStateProvider.LastRequestPeerPubkey
                    };
                    var retryTimes = 2;

                    while (true)
                    {
                        peerPubkey = GetRandomPeerPubkey(downloadBlockDto.SuggestedPeerPubkey, downloadTargetHeight,
                                                         exceptedPeers);

                        downloadResult = await DownloadBlocksAsync(peerPubkey, downloadBlockDto);

                        if (downloadResult.Success || retryTimes <= 0)
                        {
                            break;
                        }

                        exceptedPeers.Add(peerPubkey);
                        retryTimes--;
                    }

                    if (downloadResult.Success && downloadResult.DownloadBlockCount == 0)
                    {
                        await CheckBadPeerAsync(peerPubkey, downloadBlockDto.PreviousBlockHash,
                                                downloadBlockDto.PreviousBlockHeight);
                    }
                }
            }
            catch (BlockDownloadException e)
            {
                await LocalEventBus.PublishAsync(new BadPeerFoundEventData
                {
                    BlockHash   = e.BlockHash,
                    BlockHeight = e.BlockHeight,
                    PeerPubkey  = e.PeerPubkey
                });
            }

            return(downloadResult);
        }
예제 #2
0
        private bool UseSuggestedPeer(DownloadBlockDto downloadBlockDto)
        {
            if (downloadBlockDto.UseSuggestedPeer)
            {
                return(true);
            }

            var suggestedPeer        = _networkService.GetPeerByPubkey(downloadBlockDto.SuggestedPeerPubkey);
            var downloadTargetHeight = downloadBlockDto.PreviousBlockHeight + downloadBlockDto.MaxBlockDownloadCount;

            if (downloadTargetHeight > suggestedPeer.LastKnownLibHeight)
            {
                return(true);
            }

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Download and attach blocks
        /// UseSuggestedPeer == true: Download blocks from suggested peer directly;
        /// Target download height > peer lib height, download blocks from suggested peer;
        /// Target download height <= peer lib height, select a random peer to download.
        /// </summary>
        /// <param name="downloadBlockDto"></param>
        /// <returns></returns>
        public async Task <DownloadBlocksResult> DownloadBlocksAsync(DownloadBlockDto downloadBlockDto)
        {
            DownloadBlocksResult downloadResult;
            var peerPubkey = downloadBlockDto.SuggestedPeerPubkey;

            if (UseSuggestedPeer(downloadBlockDto))
            {
                downloadResult = await DownloadBlocksAsync(downloadBlockDto.PreviousBlockHash,
                                                           peerPubkey, downloadBlockDto.BatchRequestBlockCount,
                                                           downloadBlockDto.MaxBlockDownloadCount);
            }
            else
            {
                // If cannot get the blocks, there should be network problems or bad peer,
                // because we have selected peer with lib height greater than or equal to the target height.
                // 1. network problems, need to retry from other peer.
                // 2. not network problems, this peer or the last peer is bad peer, we need to remove it.
                var downloadTargetHeight =
                    downloadBlockDto.PreviousBlockHeight + downloadBlockDto.MaxBlockDownloadCount;
                var exceptedPeers = new List <string> {
                    _blockSyncStateProvider.LastRequestPeerPubkey
                };
                var retryTimes = 1;

                while (true)
                {
                    peerPubkey = GetRandomPeerPubkey(downloadBlockDto.SuggestedPeerPubkey, downloadTargetHeight,
                                                     exceptedPeers);

                    downloadResult = await DownloadBlocksAsync(downloadBlockDto.PreviousBlockHash, peerPubkey,
                                                               downloadBlockDto.BatchRequestBlockCount, downloadBlockDto.MaxBlockDownloadCount);

                    if (downloadResult.Success || retryTimes <= 0)
                    {
                        break;
                    }

                    exceptedPeers.Add(peerPubkey);
                    retryTimes--;
                }

                if (downloadResult.Success && downloadResult.DownloadBlockCount == 0)
                {
                    var checkResult = await CheckIrreversibleBlockHashAsync(downloadBlockDto.PreviousBlockHash,
                                                                            downloadBlockDto.PreviousBlockHeight);

                    if (checkResult.HasValue)
                    {
                        Logger.LogWarning(
                            $"Found bad peer: peerPubkey: {peerPubkey}, block hash: {downloadBlockDto.PreviousBlockHash}, block height: {downloadBlockDto.PreviousBlockHeight}");
                        await LocalEventBus.PublishAsync(new IncorrectIrreversibleBlockEventData
                        {
                            BlockHash         = downloadBlockDto.PreviousBlockHash,
                            BlockHeight       = downloadBlockDto.PreviousBlockHeight,
                            BlockSenderPubkey = checkResult.Value
                                ? peerPubkey
                                : _blockSyncStateProvider.LastRequestPeerPubkey
                        });
                    }
                }
            }

            return(downloadResult);
        }
예제 #4
0
        private async Task <DownloadBlocksResult> DownloadBlocksAsync(string peerPubkey,
                                                                      DownloadBlockDto downloadBlockDto)
        {
            var downloadBlockCount      = 0;
            var lastDownloadBlockHash   = downloadBlockDto.PreviousBlockHash;
            var lastDownloadBlockHeight = downloadBlockDto.PreviousBlockHeight;

            Logger.LogDebug(
                $"Download blocks start with block height: {lastDownloadBlockHeight}, hash: {lastDownloadBlockHash}, PeerPubkey: {peerPubkey}");

            while (downloadBlockCount < downloadBlockDto.MaxBlockDownloadCount)
            {
                var getBlocksResult = await _networkService.GetBlocksAsync(lastDownloadBlockHash,
                                                                           downloadBlockDto.BatchRequestBlockCount, peerPubkey);

                if (!getBlocksResult.Success)
                {
                    return(new DownloadBlocksResult
                    {
                        Success = false
                    });
                }

                var blocksWithTransactions = getBlocksResult.Payload;
                if (blocksWithTransactions == null || !blocksWithTransactions.Any())
                {
                    Logger.LogDebug(
                        $"No blocks returned from peer: {peerPubkey}, Previous block height: {lastDownloadBlockHeight}, hash: {lastDownloadBlockHash}.");
                    break;
                }

                foreach (var blockWithTransactions in blocksWithTransactions)
                {
                    Logger.LogDebug($"Processing block {blockWithTransactions}.");

                    if (blockWithTransactions.Height != lastDownloadBlockHeight + 1 ||
                        blockWithTransactions.Header.PreviousBlockHash != lastDownloadBlockHash)
                    {
                        Logger.LogWarning(
                            $"Received invalid block, peer: {peerPubkey}, block hash: {blockWithTransactions.GetHash()}, block height: {blockWithTransactions.Height}");
                        throw new BlockDownloadException(blockWithTransactions.GetHash(), blockWithTransactions.Height,
                                                         peerPubkey);
                    }

                    lastDownloadBlockHash   = blockWithTransactions.GetHash();
                    lastDownloadBlockHeight = blockWithTransactions.Height;

                    EnqueueAttachBlockJob(blockWithTransactions, peerPubkey);
                    downloadBlockCount++;
                }

                var lastBlock = blocksWithTransactions.Last();
                lastDownloadBlockHash   = lastBlock.GetHash();
                lastDownloadBlockHeight = lastBlock.Height;
            }

            if (downloadBlockCount != 0)
            {
                _blockSyncStateProvider.SetDownloadJobTargetState(lastDownloadBlockHash, false);
                _blockSyncStateProvider.LastRequestPeerPubkey = peerPubkey;
            }

            return(new DownloadBlocksResult
            {
                Success = true,
                DownloadBlockCount = downloadBlockCount,
                LastDownloadBlockHash = lastDownloadBlockHash,
                LastDownloadBlockHeight = lastDownloadBlockHeight
            });
        }
예제 #5
0
        public async Task <DownloadBlocksResult> DownloadBlocksAsync(DownloadBlockDto downloadBlockDto)
        {
            var downloadBlockCount      = 0;
            var lastDownloadBlockHash   = downloadBlockDto.PreviousBlockHash;
            var lastDownloadBlockHeight = downloadBlockDto.PreviousBlockHeight;

            while (downloadBlockCount < downloadBlockDto.MaxBlockDownloadCount)
            {
                Logger.LogDebug(
                    $"Request blocks start with block hash: {lastDownloadBlockHash}, block height: {lastDownloadBlockHeight}");

                var blocksWithTransactions = await _networkService.GetBlocksAsync(lastDownloadBlockHash,
                                                                                  downloadBlockDto.BatchRequestBlockCount, downloadBlockDto.SuggestedPeerPubkey);

                if (blocksWithTransactions == null || !blocksWithTransactions.Any())
                {
                    Logger.LogWarning("No blocks returned.");
                    break;
                }

                if (blocksWithTransactions.First().Header.PreviousBlockHash != lastDownloadBlockHash)
                {
                    throw new InvalidOperationException(
                              $"Previous block not match previous {lastDownloadBlockHash}, network back {blocksWithTransactions.First().Header.PreviousBlockHash}");
                }

                foreach (var blockWithTransactions in blocksWithTransactions)
                {
                    Logger.LogDebug($"Processing block {blockWithTransactions}.");

                    _blockSyncQueueService.Enqueue(
                        async() =>
                    {
                        await _blockSyncAttachService.AttachBlockWithTransactionsAsync(blockWithTransactions,
                                                                                       async() =>
                        {
                            _blockSyncStateProvider.TryUpdateDownloadJobTargetState(blockWithTransactions.GetHash(), true);
                        });
                    },
                        OSConstants.BlockSyncAttachQueueName);

                    downloadBlockCount++;
                }

                var lastBlock = blocksWithTransactions.Last();
                lastDownloadBlockHash   = lastBlock.GetHash();
                lastDownloadBlockHeight = lastBlock.Height;
            }

            if (lastDownloadBlockHash != null)
            {
                _blockSyncStateProvider.SetDownloadJobTargetState(lastDownloadBlockHash, false);
            }

            return(new DownloadBlocksResult
            {
                DownloadBlockCount = downloadBlockCount,
                LastDownloadBlockHash = lastDownloadBlockHash,
                LastDownloadBlockHeight = lastDownloadBlockHeight
            });
        }