Exemplo n.º 1
0
        async Task HandleBlockData(BlockData blockData, ChainSyncItem chainSyncItem, Chain.Chain chain, HashSet <NodeConnection> nodeConnections)
        {
            try
            {
                if (blockData == null)
                {
                    return;
                }

                var block             = blockData.Block;
                var blockId           = block.BlockId;
                var blockStorage      = chain.BlockStorage;
                var lastStoredBlockId = blockStorage.LastStoredBlockId;
                var chainId           = block.ChainId;
                var sync = chainSyncItem.Sync;

                if (blockId <= blockStorage.LastStoredBlockId)
                {
                    return;
                }

                lock (sync.Lock)
                {
                    if (sync.NewBlocks.Count > 0)
                    {
                        // remove older blocks
                        var first = sync.NewBlocks.First().Value;
                        while (first != null)
                        {
                            if (first.BlockId <= lastStoredBlockId)
                            {
                                sync.Remove(first.BlockId);
                            }
                            else
                            {
                                break;
                            }

                            if (sync.NewBlocks.Count > 0)
                            {
                                first = sync.NewBlocks.First().Value;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }

                if (!_coreChain.IsBlockSignatureValid(blockData))
                {
                    return;
                }

                lock (sync.Lock)
                {
                    if (sync.NewBlocks.ContainsKey(blockId))
                    {
                        var data = sync.NewBlocks[blockId];
                        data.UpdateBlockData(blockData);

                        var first = sync.NewBlocks.First().Value;

                        if (first.BlockId != blockId) // if first in the list, let it pass
                        {
                            if (first.BlockData != null)
                            {
                                TaskRunner.Run(() => HandleBlockData(first.BlockData, chainSyncItem, chain, nodeConnections));
                            }
                            return;
                        }
                    }
                }

                await sync.ConsumeLock.WaitAsync();

                var result = await blockStorage.StoreBlock(blockData);

                if (result == BlockConsumeResult.Ok)
                {
                    Log.Trace($"New block consumed {blockId}, chainid {chainId}/{block.ChainIndex} ({block.ChainType}). Last stored block id {lastStoredBlockId}.", this);
                    _chainManager.ConsumeBlockData(blockData);
                }

                sync.ConsumeLock.Release();

                if (result == BlockConsumeResult.InvalidHash)
                {
                    Log.Warn($"Valid block {blockId} for chain {chainId} with invalid hash received.", this);
                    lock (sync.Lock)
                    {
                        sync.Remove(blockId);
                        return;
                    }
                }

                nodeConnections = nodeConnections ?? new HashSet <NodeConnection>();
                lock (sync.Lock)
                {
                    if (result == BlockConsumeResult.Ok)
                    {
                        var index = sync.IndexOf(blockId);
                        if (index >= 0)
                        {
                            for (var i = 0; i <= index; i++)
                            {
                                sync.RemoveAt(0);
                            }
                        }

                        if (sync.NewBlocks.Count > 0)
                        {
                            var first = sync.NewBlocks.First().Value;
                            if (first.BlockData != null)
                            {
                                TaskRunner.Run(() => HandleBlockData(first.BlockData, chainSyncItem, chain, nodeConnections));
                            }
                        }

                        return;
                    }

                    if (sync.NewBlocks.ContainsKey(blockId))
                    {
                        return;
                    }

                    var startBlock = lastStoredBlockId + 1;
                    var endBlock   = blockId;

                    if (sync.NewBlocks.Count == 0)
                    {
                        for (var i = startBlock; i <= endBlock; i++)
                        {
                            var download = new SyncDownload(i);
                            if (download.BlockId == endBlock)
                            {
                                download.UpdateBlockData(blockData);
                            }
                            sync.Add(download.BlockId, download);

                            TaskRunner.Run(() => DownloadBlock(download.BlockId, chainSyncItem, nodeConnections));

                            if ((i - startBlock) > 50)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        var first = sync.NewBlocks.First().Value;
                        var last  = sync.NewBlocks.Last().Value;
                        var start = Math.Min(first.BlockId, startBlock);
                        var end   = Math.Max(last.BlockId, endBlock);

                        for (var i = start; i <= end; i++)
                        {
                            var added = sync.NewBlocks.TryGetValue(i, out var download);
                            if (download != null && download.TimedOut && download.BlockData == null)
                            {
                                TaskRunner.Run(() => DownloadBlock(download.BlockId, chainSyncItem, nodeConnections));
                            }

                            download = download ?? new SyncDownload(i);
                            if (download.BlockId == endBlock)
                            {
                                download.UpdateBlockData(blockData);
                            }

                            if (!added)
                            {
                                sync.Add(download.BlockId, download);
                            }

                            if ((!added || download.TimedOut) && download.BlockData == null)
                            {
                                TaskRunner.Run(() => DownloadBlock(download.BlockId, chainSyncItem, nodeConnections));
                                if (sync.NewBlocks.Count > 50)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    if (sync.NewBlocks.Count > 0)
                    {
                        var first = sync.NewBlocks.First().Value;
                        if (first.BlockData != null)
                        {
                            TaskRunner.Run(() => HandleBlockData(first.BlockData, chainSyncItem, chain, nodeConnections));
                        }
                        else if (first.TimedOut)
                        {
                            TaskRunner.Run(() => DownloadBlock(first.BlockId, chainSyncItem, nodeConnections));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.HandleException(ex, this);
            }
        }
Exemplo n.º 2
0
 public ChainSyncItem(Chain.Chain chain)
 {
     Chain = chain;
 }