async Task <bool> DownloadTransactionSlices(RemoteSyncItem remote, ChainSyncItem chainSyncItem)
        {
            var chainId    = chainSyncItem.ChainId;
            var chainType  = chainSyncItem.ChainType;
            var chainIndex = chainSyncItem.ChainIndex;

            chainSyncItem.UpdateLastBlockInfo((await remote.Client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data);

            var localStartSlice = 0;
            var localLast       = TransactionStorage.GetTransactionSlices(_storage, chainType, chainId, chainIndex, true).LastOrDefault();

            if (localLast.Value != null)
            {
                localStartSlice = localLast.Value.SliceId + 1;
            }

            var remoteLastAvailableSlice = TransactionSliceInfo.GetSliceIndex(chainSyncItem.BlockState.LastTransactionId) - 1;

            if (remoteLastAvailableSlice < 0) // -1: ignore last "hot" slice
            {
                Log.Debug($"Skipping transaction slice download for chain {chainId}/{chainIndex}, no available remote stored slice found.", this);
                return(true);
            }

            var count = 0;

            if (remoteLastAvailableSlice >= 0 && remoteLastAvailableSlice >= localStartSlice)
            {
                for (var sliceId = localStartSlice; sliceId <= remoteLastAvailableSlice; sliceId++)
                {
                    Log.Trace($"Downloading transaction slice {sliceId}/{remoteLastAvailableSlice} for chain {chainId}.", this);
                    var sliceData = (await remote.Client.DownloadTransactionSlice(_storage, chainType, chainId, chainIndex, sliceId)).Data;

                    var error = false;
                    if (sliceData == null || !sliceData.Move())
                    {
                        Log.Trace($"Slice {sliceId} download for chain {chainId}/{chainIndex} failed.", this);
                        sliceData?.Delete();
                        error = true;
                    }

                    sliceData?.Dispose();

                    if (error)
                    {
                        return(false);
                    }

                    count++;
                }
            }

            if (count > 0) // check for new slices
            {
                return(await DownloadTransactionSlices(remote, chainSyncItem));
            }

            return(true);
        }
        async Task <bool> DownloadBlockSlices(RemoteSyncItem remote, ChainSyncItem chainSyncItem)
        {
            var chainType  = chainSyncItem.ChainType;
            var chainId    = chainSyncItem.ChainId;
            var chainIndex = chainSyncItem.ChainIndex;

            chainSyncItem.UpdateLastBlockInfo((await remote.Client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data);

            var lastBlockId = chainSyncItem.BlockState.LastBlockId;

            if (lastBlockId <= Protocol.InvalidBlockId)
            {
                Log.Debug($"Skipping block slice download for chain {chainId}/{chainIndex}, blockid invalid.", this);
                return(true);
            }

            var remoteLastAvailableSlice = BlockSliceInfo.GetSliceIndex(lastBlockId) - 1;

            if (remoteLastAvailableSlice < 0) // -1: ignore last "hot" slice
            {
                Log.Debug($"Skipping block slice download for chain {chainId}/{chainIndex}, no available remote stored slice found.", this);
                return(true);
            }

            var localStartSlice = 0L;
            var localLast       = BlockStorage.GetBlockSlices(_storage, chainType, chainId, chainIndex, true).LastOrDefault();

            if (localLast.Value != null)
            {
                localStartSlice = localLast.Value.SliceIndex + 1;
            }

            if (!(chainSyncItem.LowestFoundBlockSliceId <= localStartSlice))
            {
                Log.Error($"Download block slices for chain {chainId}/{chainIndex} failed, last local slice is {localStartSlice}, lowest remote slice found is {chainSyncItem.LowestFoundBlockSliceId}.", this);
                return(false);
            }

            var count = 0;

            for (var sliceIndex = localStartSlice; sliceIndex <= remoteLastAvailableSlice; sliceIndex++)
            {
                Log.Trace($"Downloading block slice {sliceIndex}/{remoteLastAvailableSlice} for chain {chainId}/{chainIndex}.", this);
                var sliceData = (await remote.Client.DownloadBlockSlice(_storage, chainType, chainId, chainIndex, sliceIndex)).Data;

                var error = false;
                if (sliceData == null || !sliceData.Move())
                {
                    Log.Trace($"Block slice {sliceIndex} download failed.", this);
                    sliceData?.Delete();
                    error = true;
                }

                sliceData?.Dispose();

                if (error)
                {
                    return(false);
                }

                count++;
            }

            if (count > 0)
            {
                return(await DownloadBlockSlices(remote, chainSyncItem));
            }

            return(true);
        }
        async Task DownloadBlock(long blockId, ChainSyncItem chainSyncItem, HashSet <NodeConnection> nodeConnections, int tries = 0)
        {
            var retry = false;

            var sync = chainSyncItem.Sync;

            try
            {
                await sync.DownloadLock.WaitAsync();


                SyncDownload download;
                lock (sync.Lock)
                {
                    sync.NewBlocks.TryGetValue(blockId, out download);
                    if (download == null)
                    {
                        return;
                    }

                    if (!download.TimedOut && download.Downloading)
                    {
                        return;
                    }

                    download.Downloading  = true;
                    download.DownloadTime = DateTime.UtcNow;
                }

                nodeConnections = nodeConnections ?? new HashSet <NodeConnection>();

                foreach (var connection in nodeConnections)
                {
                    var nodeInfo = connection.NodeInfo;
                    if (nodeInfo.IsPublicEndPoint && nodeInfo.NodeId != _configuration.LocaleNodeInfo.NodeId)
                    {
                        var client    = new NodeClient(nodeInfo.PublicEndPoint);
                        var blockData = (await client.DownloadBlockData(chainSyncItem.ChainType, chainSyncItem.ChainId, chainSyncItem.ChainIndex, blockId)).Data;
                        if (blockData != null)
                        {
                            download.UpdateBlockData(blockData);
                            await HandleBlockData(blockData, nodeConnections);

                            goto end;
                        }
                        else
                        {
                            retry = true;
                        }
                    }
                }

                foreach (var endPoint in chainSyncItem.Chain.AvailableEndpoints)
                {
                    var client = new NodeClient(endPoint.EndPoint);
                    if (endPoint.NodeInfo == null)
                    {
                        endPoint.NodeInfo = (await client.DownloadNodeInfo(_configuration.NetworkPublicKey)).Data;
                    }

                    if (endPoint.NodeInfo != null && endPoint.NodeInfo.NodeId != _configuration.LocaleNodeInfo.NodeId)
                    {
                        var blockData = (await client.DownloadBlockData(chainSyncItem.ChainType, chainSyncItem.ChainId, chainSyncItem.ChainIndex, blockId)).Data;
                        if (blockData != null)
                        {
                            download.UpdateBlockData(blockData);
                            await HandleBlockData(blockData, nodeConnections);

                            goto end;
                        }
                        else
                        {
                            retry = true;
                        }
                    }
                }

                foreach (var connection in nodeConnections)
                {
                    await connection.Send(new NodeBlockDataRequestMessage(chainSyncItem.ChainType, blockId, chainSyncItem.ChainId, chainSyncItem.ChainIndex) { SignKey = _configuration.LocaleNodePrivateKey });

                    await Task.Delay(50);
                }

end:
                lock (sync.Lock)
                {
                    download.Downloading = false;
                }
            }
            catch (Exception ex)
            {
                Log.HandleException(ex);
            }
            finally
            {
                sync.DownloadLock.Release();
            }

            if (retry && tries < 10)
            {
                await Task.Delay(50 *(tries + 1));

                TaskRunner.Run(() => DownloadBlock(blockId, chainSyncItem, nodeConnections, tries + 1));
            }
        }
        async Task <bool> DownloadBlocks(RemoteSyncItem remote, ChainSyncItem chainSyncItem)
        {
            var chainType  = chainSyncItem.ChainType;
            var chainId    = chainSyncItem.ChainId;
            var chainIndex = chainSyncItem.ChainIndex;

            chainSyncItem.UpdateLastBlockInfo((await remote.Client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data);

            var chain            = _chainManager.GetChain(chainSyncItem.ChainType, chainId, chainIndex);
            var lastChainBlockId = chainSyncItem.BlockState.LastBlockId;

            var lastBlock   = chain.BlockStorage.LastBlock;
            var nextBlockId = Protocol.GenesisBlockId;

            if (lastBlock != null)
            {
                nextBlockId = lastBlock.BlockId + 1;
            }

            var sync      = chainSyncItem.Sync;
            var newBlocks = chainSyncItem.Sync.NewBlocks;
            var lockitem  = chainSyncItem.Sync.Lock;

            var count = 0;

            for (var blockId = nextBlockId; blockId <= lastChainBlockId; blockId++)
            {
                Log.Trace($"Downloading block {blockId}/{lastChainBlockId} for chain {chainId}/{chainIndex}.", this);

                var blockData = (await remote.Client.DownloadBlockData(chainType, chainId, chainIndex, blockId)).Data;
                if (blockData == null)
                {
                    Log.Trace($"Block {blockId} download failed.", this);
                    return(false);
                }

                //await HandleBlock(blockData, null);
                lock (lockitem)
                {
                    if (newBlocks.TryGetValue(blockId, out var dl))
                    {
                        if (dl.BlockData == null)
                        {
                            dl.UpdateBlockData(blockData);
                        }
                    }
                    else
                    {
                        sync.Add(blockId, new SyncDownload(blockId).UpdateBlockData(blockData));
                    }
                }
                count++;
            }

            if (newBlocks.ContainsKey(nextBlockId))
            {
                var last = chainSyncItem.Sync.NewBlocks[nextBlockId];
                await HandleBlockData(last.BlockData, null);
            }

            if (count > 0)
            {
                return(await DownloadBlocks(remote, chainSyncItem));
            }

            return(true);
        }
Esempio n. 5
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);
            }
        }
Esempio n. 6
0
        async Task <Dictionary <Tuple <int, uint, ChainType>, ChainSyncItem> > GetChainSyncItems()
        {
            var chains = new List <Chain.Chain> {
                _chainManager.CoreChain
            };

            chains.AddRange(_chainManager.ServiceChains.Values);
            chains.AddRange(_chainManager.DataChains.Values);
            chains.AddRange(_chainManager.MaintainChains.Values);

            var chainSyncs = new Dictionary <Tuple <int, uint, ChainType>, ChainSyncItem>();
            var remotes    = new List <RemoteSyncItem>();

            foreach (var chain in chains)
            {
                var chainType  = chain.ChainType;
                var chainId    = chain.ChainId;
                var chainIndex = chain.ChainIndex;

                var chainSync = new ChainSyncItem(chain);
                chainSyncs.Add(new Tuple <int, uint, ChainType>(chainId, chainIndex, chainType), chainSync);

                Chain.Chain.CreateRequiredDirectories(_storage, chain.ChainType, chainId, chainIndex, true);

                var endPoints = chain.AvailableEndpoints;
                foreach (var endPoint in endPoints)
                {
                    var client   = new NodeClient(endPoint.EndPoint);
                    var nodeInfo = endPoint.NodeInfo;
                    if (nodeInfo == null)
                    {
                        nodeInfo = (await client.DownloadNodeInfo(_configuration.NetworkPublicKey)).Data;
                    }

                    if (nodeInfo != null && !(nodeInfo.NodeId == _configuration.LocaleNodeInfo.NodeId))
                    {
                        if (endPoint.NodeInfo == null)
                        {
                            endPoint.NodeInfo = nodeInfo;
                        }

                        var lastBlockInfo = (await client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data;
                        if (lastBlockInfo != null)
                        {
                            var blockSliceInfo       = (await client.DownloadBlockStorageSliceInfo(chainType, chainId, chainIndex)).Data;
                            var transactionSliceInfo = (await client.DownloadTransactionStorageSliceInfo(chainType, chainId, chainIndex)).Data;

                            var remote = new RemoteSyncItem(client, lastBlockInfo);
                            chainSync.AddRemote(remote);

                            if (blockSliceInfo != null)
                            {
                                chainSync.UpdateLowestFoundBlockSliceId(blockSliceInfo.FirstStoredSliceId);
                            }
                            if (transactionSliceInfo != null)
                            {
                                chainSync.UpdateLowestFoundTransactionSliceId(transactionSliceInfo.FirstStoredSliceId);
                            }

                            remotes.Add(remote);
                        }
                    }
                }
            }

            // get latest chain info
            foreach (var chain in chainSyncs.Values)
            {
                var chainType  = chain.ChainType;
                var chainId    = chain.ChainId;
                var chainIndex = chain.ChainIndex;

                foreach (var remote in chain.Remotes)
                {
                    var lastBlockInfo = (await remote.Client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data;
                    chain.UpdateLastBlockInfo(lastBlockInfo);
                }
            }

            return(chainSyncs);
        }