Пример #1
0
        private async Task DownloadNextBlocks(Node node, CancellationToken ctsToken, int maxBlocksToDownload = 1)
        {
            var heights = new List <Height>();

            try
            {
                await _sem.WaitAsync(ctsToken).ConfigureAwait(false);

                if (BlocksToDownload.Count == 0)
                {
                    await Task.Delay(100, ctsToken).ContinueWith(tsk => { }).ConfigureAwait(false);

                    return;
                }

                if (BlocksToDownload.Count < maxBlocksToDownload * 2)
                {
                    maxBlocksToDownload = 1;
                }

                for (int i = 0; i < maxBlocksToDownload; i++)
                {
                    // todo check if we have that much block
                    var height = BlocksToDownload.Min();
                    BlocksToDownload.TryRemove(height);
                    heights.Add(height);
                }
            }
            finally
            {
                _sem.Release();
            }
            try
            {
                var headers = new HashSet <ChainedBlock>();
                foreach (var height in heights)
                {
                    WalletJob.TryGetHeader(height, out ChainedBlock neededHeader);
                    headers.Add(neededHeader);
                }

                var delayMinutes     = heights.Count;
                var timeoutToken     = new CancellationTokenSource(TimeSpan.FromMinutes(delayMinutes)).Token;
                var downloadCtsToken = CancellationTokenSource.CreateLinkedTokenSource(timeoutToken, ctsToken).Token;

                HashSet <Block> blocks = null;
                try
                {
                    blocks = new HashSet <Block>(await Task.Run(() => node.GetBlocks(headers.ToArray(), downloadCtsToken)).ConfigureAwait(false));
                }
                catch
                {
                    if (timeoutToken.IsCancellationRequested)
                    {
                        node.DisconnectAsync($"Block download time > {delayMinutes}min");
                    }
                    else
                    {
                        node.DisconnectAsync("Block download failed");
                    }
                    blocks = null;
                }
                if (blocks == null)
                {
                    foreach (var height in heights)
                    {
                        BlocksToDownload.Add(height);
                    }
                }
                else
                {
                    int i = 0;
                    foreach (var block in blocks)
                    {
                        DownloadedBlocks.AddOrReplace(heights[i], block);
                        i++;
                    }
                }
            }
            catch
            {
                try
                {
                    await _sem.WaitAsync(ctsToken).ConfigureAwait(false);

                    foreach (var height in heights)
                    {
                        BlocksToDownload.Add(height);
                    }
                }
                finally
                {
                    _sem.Release();
                }
            }
        }