private async Task ProcessBlockRequest(uint height, PeerConnection peer)
        {
            var header = await _blockRepository.GetPrimaryHeader(height);

            if (header != null)
            {
                _logger.LogInformation($"Responding to block request {height} with {BitConverter.ToString(header.BlockId)}");
                var block = await _blockRepository.GetBlock(header.BlockId);

                var data = SerializeObject(block);
                SendBlock(peer, data, false);
            }
            else
            {
                _logger.LogInformation($"Unable to respond to block request {height}");
            }
        }
 private void Peer_OnDisconnect(PeerConnection sender)
 {
     _peerEvent.WaitOne();
     try
     {
         _logger.LogInformation($"Peer disconnect {sender.RemoteId} {sender.RemoteEndPoint}");
         _peerConnections.Remove(sender);
         sender.Close();
     }
     catch (Exception ex)
     {
         _logger.LogError($"Disconnect error ({sender.RemoteId}) - {ex.Message}");
     }
     finally
     {
         _peerEvent.Set();
     }
 }
        private void Peer_OnIdentify(PeerConnection sender)
        {
            _logger.LogInformation($"Peer identify {sender.RemoteEndPoint} - {sender.RemoteId}");

            if (!string.IsNullOrEmpty(sender.ConnectionString))
            {
                var peers = _peerRoundRobin.Where(x => x.ConnectionString == sender.ConnectionString);
                foreach (var peer in peers)
                {
                    peer.NodeId = sender.RemoteId;
                }
            }

            //remove duplicate connections
            lock (_duplicateLock)
            {
                var peers = GetActivePeers();
                foreach (var peer in peers.Where(x => x.RemoteId == sender.RemoteId && x != sender))
                {
                    peer.Disconnect();
                    peer.Close();
                }
            }

            //remove connection to self
            if (sender.RemoteId == NodeId)
            {
                if (!string.IsNullOrEmpty(sender.ConnectionString))
                {
                    var selfs = _peerRoundRobin.Where(x => x.ConnectionString == sender.ConnectionString);
                    foreach (var self in selfs)
                    {
                        self.IsSelf = true;
                    }
                }
                sender.Disconnect();
                sender.Close();
            }
        }
        private async Task ProcessBlockRequest(byte[] blockId, bool next, PeerConnection peer)
        {
            Block block = null;

            if (next)
            {
                block = await _blockRepository.GetNextBlock(blockId);
            }
            else
            {
                block = await _blockRepository.GetBlock(blockId);
            }

            if (block != null)
            {
                _logger.LogInformation($"Responding to block request {next} {BitConverter.ToString(blockId)}");
                var data = SerializeObject(block);
                SendBlock(peer, data, false);
            }
            else
            {
                _logger.LogInformation($"Unable to respond to block request {next} {BitConverter.ToString(blockId)}");
            }
        }
        public void Open()
        {
            _cancelTokenSource = new CancellationTokenSource();
            _listener          = new TcpListener(IPAddress.Any, (int)_port);
            _listener.Start();

            Task.Factory.StartNew(async() =>
            {
                try
                {
                    while (!_cancelTokenSource.IsCancellationRequested)
                    {
                        var client = await _listener.AcceptTcpClientAsync();
                        _logger.LogDebug($"Client connected - {client.Client.RemoteEndPoint}");
                        var peer = new PeerConnection(_serviceId, _version, NodeId, client);
                        AttachEventHandlers(peer);
                        _peerEvent.WaitOne();
                        try
                        {
                            _peerConnections.Add(peer);
                            peer.Run();
                        }
                        finally
                        {
                            _peerEvent.Set();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError($"Error listening - {ex.Message}");
                }
            });

            DiscoverOwnConnectionStrings();
            AdvertiseToPeers();

            _discoveryTimer = new Timer(async(state) =>
            {
                await DiscoverPeers();
            }, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(30));

            _sharePeersTimer = new Timer(SharePeers, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));


            Task.Factory.StartNew(async() =>
            {
                while (!_cancelTokenSource.IsCancellationRequested)
                {
                    await Task.Delay(TimeSpan.FromMinutes(5));
                    var peers = GetActivePeers();
                    _logger.LogInformation($"Check in - Outgoing peers: {peers.Count(x => x.Outgoing)}");
                    _logger.LogInformation($"Check in - Incoming peers: {peers.Count(x => !x.Outgoing)}");

                    //var process = Process.GetCurrentProcess();

                    //_logger.LogInformation($"Check in - Thread count: {process.Threads.Count}");
                    //_logger.LogInformation($"Check in - Working set: {process.WorkingSet64}");
                    //_logger.LogInformation($"Check in - PrivateMemorySize: {process.PrivateMemorySize64}");
                }
            });
        }
 private void Peer_OnPeerException(PeerConnection sender, Exception exception)
 {
     _logger.LogError($"Peer exception {sender.RemoteEndPoint} - {exception.Message}");
 }
 private void Peer_OnUnresponsive(PeerConnection sender)
 {
     _logger.LogInformation($"Unresponsive peer {sender.RemoteEndPoint}");
 }