Esempio n. 1
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task Synchronize()
        {
            if (SyncRunning)
            {
                return;
            }
            SyncRunning = true;
            _logger.Here().Information("Trying to Synchronize");
            try
            {
                Dictionary <ulong, Peer> peers;
                const int retryCount   = 5;
                var       currentRetry = 0;
                var       jitterer     = new Random();
                for (; ;)
                {
                    peers = await _localNode.GetPeers();

                    if (peers.Count == 0)
                    {
                        _logger.Here().Warning("Peer count is zero. It's possible serf is busy... Retrying");
                        currentRetry++;
                    }

                    if (currentRetry > retryCount || peers.Count != 0)
                    {
                        break;
                    }

                    var retryDelay = TimeSpan.FromSeconds(Math.Pow(2, currentRetry)) +
                                     TimeSpan.FromMilliseconds(jitterer.Next(0, 1000));
                    await Task.Delay(retryDelay);
                }

                var localBlockHeight = await _unitOfWork.HashChainRepository.CountAsync();

                var localLastBlock = await _unitOfWork.HashChainRepository.GetAsync(b =>
                                                                                    new ValueTask <bool>(b.Height == (ulong)localBlockHeight));

                var localLastBlockHash = string.Empty;
                if (localLastBlock != null)
                {
                    localLastBlockHash = BitConverter.ToString(localLastBlock.ToHash());
                }

                Task <BlockHashPeer>[] networkPeerTasks;

                if (_syncWithSeedNodes)
                {
                    networkPeerTasks =
                        _localNode.SerfClient.SeedNodes.Seeds.Select(seed =>
                                                                     _networkClient.GetPeerLastBlockHashAsync(peers.First(x =>
                                                                                                                          x.Value.Host.Contains(seed[..^ seed.IndexOf(":", StringComparison.Ordinal)])).Value))
Esempio n. 2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="blockGraph"></param>
        /// <returns></returns>
        private async Task Publish(BlockGraph blockGraph)
        {
            Guard.Argument(blockGraph, nameof(blockGraph)).NotNull();
            try
            {
                var peers = await _localNode.GetPeers();

                await _localNode.Broadcast(peers.Values.ToArray(), TopicType.AddBlockGraph,
                                           Helper.Util.SerializeFlatBuffer(blockGraph));
            }
            catch (Exception ex)
            {
                _logger.Here().Error(ex, "Publish error");
            }
        }
Esempio n. 3
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task Synchronize()
        {
            if (SyncRunning)
            {
                return;
            }
            SyncRunning = true;
            _logger.Here().Information("Trying to Synchronize");
            try
            {
                Dictionary <ulong, Peer> peers;
                const int retryCount   = 5;
                var       currentRetry = 0;
                var       jitterer     = new Random();
                for (; ;)
                {
                    peers = await _localNode.GetPeers();

                    if (peers.Count == 0)
                    {
                        _logger.Here().Warning("Peer count is zero. It's possible serf is busy... Retrying");
                        currentRetry++;
                    }

                    if (currentRetry > retryCount || peers.Count != 0)
                    {
                        break;
                    }

                    var retryDelay = TimeSpan.FromSeconds(Math.Pow(2, currentRetry)) +
                                     TimeSpan.FromMilliseconds(jitterer.Next(0, 1000));
                    await Task.Delay(retryDelay);
                }

                var localBlockHeight = await _unitOfWork.HashChainRepository.CountAsync();

                var localLastBlock = await _unitOfWork.HashChainRepository.GetAsync(b =>
                                                                                    new ValueTask <bool>(b.Height == localBlockHeight));

                var localLastBlockHash = string.Empty;
                if (localLastBlock != null)
                {
                    localLastBlockHash = BitConverter.ToString(localLastBlock.ToHash());
                }

                var networkPeerTasks =
                    peers.Values.Select(peer => _networkClient.GetPeerLastBlockHashAsync(peer)).ToArray();

                var networkBlockHashes =
                    new List <BlockHashPeer>(await Task.WhenAll(networkPeerTasks))
                    .Where(element => element != null);

                var networkBlockHashesGrouped = networkBlockHashes
                                                .Where(hash => hash != null)
                                                .GroupBy(hash => new
                {
                    Hash   = BitConverter.ToString(hash.BlockHash.Hash),
                    Height = hash.BlockHash.Height,
                })
                                                .Select(hash => new
                {
                    Hash   = hash.Key.Hash,
                    Height = hash.Key.Height,
                    Count  = hash.Count()
                })
                                                .OrderByDescending(element => element.Count)
                                                .ThenBy(element => element.Height);

                var numPeersWithSameHash = networkBlockHashesGrouped
                                           .FirstOrDefault(element => element.Hash == localLastBlockHash)?
                                           .Count ?? 0;

                if (!networkBlockHashes.Any())
                {
                    _logger.Here().Information("No remote block hashes found");
                }
                else if (numPeersWithSameHash > networkBlockHashes.Count() / 2.0)
                {
                    _logger.Here().Information("Local node has same hash {@Hash} as majority of the network ({@NumSameHash} / {@NumPeers})",
                                               localLastBlockHash, numPeersWithSameHash, networkBlockHashes.Count());
                }
                else
                {
                    _logger.Here().Information(
                        "Local node does not have same hash {@Hash} as majority of the network ({@NumSameHash} / {@NumPeers})",
                        localLastBlockHash, numPeersWithSameHash, networkBlockHashes.Count());

                    foreach (var hash in networkBlockHashesGrouped)
                    {
                        _logger.Here().Debug("Hash {@Hash} with height {@Height} found {@Count} times", hash.Hash, hash.Height, hash.Count);
                    }

                    var synchronized = false;
                    foreach (var hash in networkBlockHashesGrouped)
                    {
                        foreach (var peer in networkBlockHashes.Where(element =>
                                                                      BitConverter.ToString(element.BlockHash.Hash) == hash.Hash &&
                                                                      element.BlockHash.Height == hash.Height))
                        {
                            _logger.Here().Debug(
                                "Synchronizing chain with last block hash {@Hash} and height {@Height} from {@Peer} {@Version} {@Host}",
                                hash.Hash, hash.Height, peer.Peer.NodeName, peer.Peer.NodeVersion, peer.Peer.Host);

                            synchronized = await Synchronize(peer.Peer.Host, localBlockHeight, hash.Height);

                            if (synchronized)
                            {
                                _logger.Here().Information("Successfully synchronized with {@Peer} {@Version} {@Host}",
                                                           peer.Peer.NodeName, peer.Peer.NodeVersion, peer.Peer.Host);

                                break;
                            }
                        }

                        if (synchronized)
                        {
                            break;
                        }
                    }

                    if (!synchronized)
                    {
                        _logger.Here().Error("Unable to synchronize with remote peers");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Here().Error(ex, "Error while checking");
            }

            _logger.Here().Information("Finish Synchronizing");
            SyncRunning = false;
        }