/// <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))
/// <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"); } }
/// <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; }