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); } }
public ChainSyncItem(Chain.Chain chain) { Chain = chain; }