示例#1
0
        public async Task DialPeerAsync_GoodPeer_ShouldBeInPool()
        {
            IpEndPointHelper.TryParse(NetworkTestConstants.GoodPeerEndpoint, out var endpoint);

            // two different hosts with the same pubkey.
            var added = await _networkServer.ConnectAsync(endpoint);

            added.ShouldBeTrue();
            _peerPool.FindPeerByEndpoint(endpoint).ShouldNotBeNull();
        }
示例#2
0
        public void AddedPeer_IsFindable_ByAddressAndPubkey()
        {
            var peer = CreatePeer();

            _peerPool.TryAddPeer(peer);

            _peerPool.PeerCount.ShouldBe(1);
            _peerPool.FindPeerByEndpoint(peer.RemoteEndpoint).ShouldNotBeNull();
            _peerPool.FindPeerByPublicKey(peer.Info.Pubkey).ShouldNotBeNull();
        }
        public async Task Connect_InboundPeerIsLater_Test()
        {
            var peer = CreatePeerAndAddToPeerPool();

            peer.UpdateLastReceivedHandshake(new Handshake
            {
                HandshakeData = new HandshakeData
                {
                    LastIrreversibleBlockHeight = 1,
                    BestChainHash   = HashHelper.ComputeFrom("BestChainHash"),
                    BestChainHeight = 10,
                    Time            = TimestampHelper.GetUtcNow().AddMinutes(1)
                }
            });

            AElfPeerEndpointHelper.TryParse(NetworkTestConstants.GoodPeerEndpoint, out var endpoint);

            var added = await _connectionService.ConnectAsync(endpoint);

            added.ShouldBeTrue();

            var currentPeer = _peerPool.FindPeerByEndpoint(endpoint);

            currentPeer.ShouldNotBeNull();

            AElfPeerEndpointHelper.TryParse(NetworkTestConstants.FakeIpEndpoint, out endpoint);
            currentPeer = _peerPool.FindPeerByEndpoint(endpoint);
            currentPeer.ShouldBeNull();
        }
        private async Task <GrpcPeer> GetDialedPeerWithEndpointAsync(DnsEndPoint endpoint)
        {
            var peer = _peerPool.FindPeerByEndpoint(endpoint);

            if (peer != null)
            {
                if (peer.IsInvalid)
                {
                    _peerPool.RemovePeer(peer.Info.Pubkey);
                    await peer.DisconnectAsync(false);
                }
                else
                {
                    Logger.LogWarning($"Peer with endpoint {endpoint} is already in the pool.");
                    return(null);
                }
            }

            if (_peerPool.IsPeerBlackListed(endpoint.Host))
            {
                Logger.LogDebug($"Peer with endpoint {endpoint} is blacklisted.");
                return(null);
            }

            var dialedPeer = await _peerDialer.DialPeerAsync(endpoint);

            if (dialedPeer == null)
            {
                Logger.LogDebug($"Error dialing {endpoint}.");
                return(null);
            }

            return(dialedPeer);
        }
        public void QueryPeers_Test()
        {
            var    commonHost     = "12.34.56.67";
            string commonPort     = "1900";
            string commonEndpoint = commonHost + ":" + commonPort;

            var peer1 = CreatePeer(commonEndpoint);

            _peerPool.TryAddPeer(peer1);
            var peer2 = CreatePeer(commonEndpoint);

            _peerPool.TryAddPeer(peer2);
            var peer3 = CreatePeer("12.34.56.64:1900");

            _peerPool.TryAddPeer(peer3);
            var peer4 = CreatePeer("12.34.56.61:1900", isReady: false);

            _peerPool.TryAddPeer(peer4);

            var peers = _peerPool.GetPeers();

            peers.Count.ShouldBe(3);

            peers = _peerPool.GetPeers(true);
            peers.Count.ShouldBe(4);

            peers = _peerPool.GetPeersByHost(commonHost);
            peers.Count.ShouldBe(2);
            peers.ShouldContain(peer1);
            peers.ShouldContain(peer2);

            var peer = _peerPool.FindPeerByEndpoint(peer3.RemoteEndpoint);

            peer.ShouldBe(peer3);

            peer = _peerPool.FindPeerByPublicKey(peer3.Info.Pubkey);
            peer.ShouldBe(peer3);
        }
示例#6
0
        public async Task ProcessPeerDiscoveryJob_Test()
        {
            var node1 = new NodeInfo
            {
                Endpoint = "192.168.100.1:8001",
                Pubkey   = ByteString.CopyFromUtf8("node1")
            };
            await _peerDiscoveryService.AddNodeAsync(node1);

            await RunDiscoveryWorkerAsync();

            var endpointString = "192.168.100.100:8003";
            var nodeList       = await _peerDiscoveryService.GetNodesAsync(10);

            nodeList.Nodes.Count.ShouldBe(1);
            nodeList.Nodes[0].Endpoint.ShouldBe(endpointString);
            nodeList.Nodes[0].Pubkey.ShouldBe(ByteString.CopyFromUtf8(endpointString));

            AElfPeerEndpointHelper.TryParse(endpointString, out var aelEndpoint);
            var peer = _peerPool.FindPeerByEndpoint(aelEndpoint);

            peer.ShouldNotBeNull();
        }
        public async Task <bool> RemovePeerByEndpointAsync(string endpoint, int removalSeconds = NetworkConstants.DefaultPeerRemovalSeconds)
        {
            if (!AElfPeerEndpointHelper.TryParse(endpoint, out DnsEndPoint aelfPeerEndpoint))
            {
                return(false);
            }

            var peer = _peerPool.FindPeerByEndpoint(aelfPeerEndpoint);

            if (!await TryRemovePeerAsync(peer, removalSeconds))
            {
                Logger.LogWarning($"Remove peer failed. Peer address: {endpoint}");
                return(false);
            }

            return(true);
        }
示例#8
0
        public async Task <bool> RemovePeerAsync(string address)
        {
            if (!AElfPeerEndpointHelper.TryParse(address, out DnsEndPoint endpoint))
            {
                return(false);
            }

            var peer = _peerPool.FindPeerByEndpoint(endpoint);

            if (peer == null)
            {
                Logger.LogWarning($"Could not find peer at address {address}");
                return(false);
            }

            await _networkServer.DisconnectAsync(peer);

            return(true);
        }
示例#9
0
        private async Task <GrpcPeer> GetDialedPeerWithEndpointAsync(DnsEndPoint endpoint)
        {
            if (_peerPool.FindPeerByEndpoint(endpoint) != null)
            {
                Logger.LogWarning($"Peer with endpoint {endpoint} is already in the pool.");
                return(null);
            }

            if (_peerPool.IsPeerBlackListed(endpoint.Host))
            {
                Logger.LogWarning($"Peer with endpoint {endpoint} is blacklisted.");
                return(null);
            }

            var dialedPeer = await _peerDialer.DialPeerAsync(endpoint);

            if (dialedPeer == null)
            {
                Logger.LogWarning($"Error dialing {endpoint}.");
                return(null);
            }

            return(dialedPeer);
        }
示例#10
0
        internal async Task DoReconnectionJobAsync()
        {
            CheckNtpClockDrift();

            await _networkService.CheckPeersHealthAsync();

            var peersToConnect = _reconnectionService.GetPeersReadyForReconnection(TimestampHelper.GetUtcNow());

            if (peersToConnect.Count <= 0)
            {
                return;
            }

            foreach (var peerToConnect in peersToConnect)
            {
                string peerEndpoint = peerToConnect.Endpoint;
                if (!AElfPeerEndpointHelper.TryParse(peerEndpoint, out var parsed))
                {
                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogWarning($"Invalid {peerEndpoint}.");
                    }

                    continue;
                }

                // check that we haven't already reconnected to this node
                if (_peerPool.FindPeerByEndpoint(parsed) != null)
                {
                    Logger.LogDebug($"Peer {peerEndpoint} already in the pool, no need to reconnect.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find to {peerEndpoint}.");
                    }

                    continue;
                }

                Logger.LogDebug($"Starting reconnection to {peerToConnect.Endpoint}.");

                var connected = false;

                try
                {
                    connected = await _networkService.AddPeerAsync(peerEndpoint);
                }
                catch (Exception ex)
                {
                    // down the stack the AddPeerAsync rethrows any exception,
                    // in order to continue this job, Exception has to be catched for now.
                    Logger.LogInformation(ex, $"Could not re-connect to {peerEndpoint}.");
                }

                if (connected)
                {
                    Logger.LogDebug($"Reconnection to {peerEndpoint} succeeded.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find {peerEndpoint}.");
                    }
                }
                else
                {
                    var timeExtension = _networkOptions.PeerReconnectionPeriod * (int)Math.Pow(2, ++peerToConnect.RetryCount);
                    peerToConnect.NextAttempt = TimestampHelper.GetUtcNow().AddMilliseconds(timeExtension);

                    // if the option is set, verify that the next attempt does not exceed
                    // the maximum reconnection time.
                    if (_networkOptions.MaximumReconnectionTime != 0)
                    {
                        var maxReconnectionDate = peerToConnect.DisconnectionTime +
                                                  TimestampHelper.DurationFromMilliseconds(_networkOptions.MaximumReconnectionTime);

                        if (peerToConnect.NextAttempt > maxReconnectionDate)
                        {
                            _reconnectionService.CancelReconnection(peerEndpoint);
                            Logger.LogDebug($"Maximum reconnection time reached {peerEndpoint}, " +
                                            $"next was {peerToConnect.NextAttempt}.");

                            continue;
                        }
                    }

                    Logger.LogDebug($"Could not connect to {peerEndpoint}, next attempt {peerToConnect.NextAttempt}, " +
                                    $"current retries {peerToConnect.RetryCount}.");
                }
            }

            void CheckNtpClockDrift()
            {
                try
                {
                    _networkService.CheckNtpDrift();
                }
                catch (Exception)
                {
                    // swallow any exception, we are not interested in anything else than valid checks.
                }
            }
        }
示例#11
0
        /// <summary>
        /// Connects to a node with the given ip address and adds it to the node's peer pool.
        /// </summary>
        /// <param name="endpoint">the ip address of the distant node</param>
        /// <returns>True if the connection was successful, false otherwise</returns>
        public async Task <bool> ConnectAsync(DnsEndPoint endpoint)
        {
            Logger.LogDebug($"Attempting to reach {endpoint}.");

            if (_peerPool.FindPeerByEndpoint(endpoint) != null)
            {
                Logger.LogWarning($"Peer with endpoint {endpoint} is already in the pool.");
                return(false);
            }

            if (_peerPool.IsPeerBlackListed(endpoint.Host))
            {
                Logger.LogWarning($"Peer with endpoint {endpoint} is blacklisted.");
                return(false);
            }

            var dialedPeer = await _peerDialer.DialPeerAsync(endpoint);

            if (dialedPeer == null)
            {
                Logger.LogWarning($"Error dialing {endpoint}.");
                return(false);
            }

            var inboundPeer = _peerPool.FindPeerByPublicKey(dialedPeer.Info.Pubkey) as GrpcPeer;

            /* A connection already exists, this can happen when both peers dial each other at the same time. To make
             * sure both sides close the same connection, they both decide based on the times of the handshakes.
             * Scenario steps, chronologically:
             *  1) P1 (hsk_time: t1) --> dials P2 --and-- P1 <-- P2 dials (hsk_time: t2)
             *  2) P2 receives P1s dial with t1 (in the hsk) and add to the pool
             *  3) P1 receives P2s dial with and adds to pool
             *  4) both dials finish and find that the pool already contains the dialed node.
             * To resolve this situation, both peers will choose the connection that was initiated the earliest,
             * so either P1s dial or P2s. */

            GrpcPeer currentPeer = dialedPeer;

            if (inboundPeer != null)
            {
                Logger.LogWarning("Duplicate peer connection detected: " +
                                  $"{inboundPeer} ({inboundPeer.LastReceivedHandshakeTime}) " +
                                  $"vs {dialedPeer} ({dialedPeer.LastSentHandshakeTime}).");

                if (inboundPeer.LastReceivedHandshakeTime > dialedPeer.LastSentHandshakeTime)
                {
                    // we started the dial first, replace the inbound connection with the dialed
                    if (!_peerPool.TryReplace(inboundPeer.Info.Pubkey, inboundPeer, dialedPeer))
                    {
                        Logger.LogWarning("Replacing the inbound connection failed.");
                    }

                    await inboundPeer.DisconnectAsync(false);

                    Logger.LogWarning($"Replaced the inbound connection with the dialed peer {inboundPeer} .");
                }
                else
                {
                    // keep the inbound connection
                    await dialedPeer.DisconnectAsync(false);

                    currentPeer = inboundPeer;

                    Logger.LogWarning($"Disconnected dialed peer {dialedPeer}.");
                }
            }
            else
            {
                if (!_peerPool.TryAddPeer(dialedPeer))
                {
                    Logger.LogWarning($"Peer add to the failed {dialedPeer.Info.Pubkey}.");
                    await dialedPeer.DisconnectAsync(false);

                    return(false);
                }

                Logger.LogDebug($"Added to pool {dialedPeer.RemoteEndpoint} - {dialedPeer.Info.Pubkey}.");
            }

            try
            {
                await currentPeer.ConfirmHandshakeAsync();
            }
            catch (Exception e)
            {
                Logger.LogError(e, $"Confirm handshake error. Peer: {currentPeer.Info.Pubkey}.");
                _peerPool.RemovePeer(currentPeer.Info.Pubkey);
                await currentPeer.DisconnectAsync(false);

                throw;
            }

            currentPeer.IsConnected = true;
            currentPeer.SyncState   = SyncState.Syncing;

            Logger.LogInformation($"Connected to: {currentPeer.RemoteEndpoint} - {currentPeer.Info.Pubkey.Substring(0, 45)}" +
                                  $" - in-token {currentPeer.InboundSessionId?.ToHex()}, out-token {currentPeer.OutboundSessionId?.ToHex()}" +
                                  $" - LIB height {currentPeer.LastKnownLibHeight}" +
                                  $" - best chain [{currentPeer.CurrentBlockHeight}, {currentPeer.CurrentBlockHash}]");

            FireConnectionEvent(currentPeer);

            return(true);
        }
示例#12
0
        /// <summary>
        /// Connects to a node with the given ip address and adds it to the node's peer pool.
        /// </summary>
        /// <param name="endpoint">the ip address of the distant node</param>
        /// <returns>True if the connection was successful, false otherwise</returns>
        public async Task <bool> ConnectAsync(IPEndPoint endpoint)
        {
            Logger.LogTrace($"Attempting to reach {endpoint}.");

            if (_peerPool.FindPeerByEndpoint(endpoint) != null)
            {
                Logger.LogWarning($"Peer {endpoint} is already in the pool.");
                return(false);
            }

            GrpcPeer peer;

            try
            {
                // create the connection to the distant node
                peer = await _peerDialer.DialPeerAsync(endpoint);
            }
            catch (PeerDialException ex)
            {
                Logger.LogError(ex, $"Dial exception {endpoint}:");
                return(false);
            }

            var peerPubkey = peer.Info.Pubkey;

            if (!_peerPool.TryAddPeer(peer))
            {
                Logger.LogWarning($"Peer {peerPubkey} is already in the pool.");
                await peer.DisconnectAsync(false);

                return(false);
            }

            Handshake peerHandshake;

            try
            {
                peerHandshake = await peer.DoHandshakeAsync(await _handshakeProvider.GetHandshakeAsync());
            }
            catch (NetworkException ex)
            {
                Logger.LogError(ex, $"Handshake failed to {endpoint} - {peerPubkey}.");
                await DisconnectAsync(peer);

                return(false);
            }

            HandshakeError handshakeError = ValidateHandshake(peerHandshake, peerPubkey);

            if (handshakeError != HandshakeError.HandshakeOk)
            {
                Logger.LogWarning($"Invalid handshake [{handshakeError}] from {endpoint} - {peerPubkey}");
                await DisconnectAsync(peer);

                return(false);
            }

            Logger.LogTrace($"Connected to {peer} - LIB height {peer.LastKnownLibHeight}, " +
                            $"best chain [{peer.CurrentBlockHeight}, {peer.CurrentBlockHash}].");

            FireConnectionEvent(peer);

            return(true);
        }
示例#13
0
        internal async Task DoReconnectionJobAsync()
        {
            CheckNtpClockDrift();

            await _networkService.SendHealthChecksAsync();

            var peersToConnect = _reconnectionService.GetPeersReadyForReconnection(TimestampHelper.GetUtcNow());

            if (peersToConnect.Count <= 0)
            {
                Logger.LogDebug("No peers to reconnect.");
                return;
            }

            foreach (var peerToConnect in peersToConnect)
            {
                string peerEndpoint = peerToConnect.Endpoint;
                if (!AElfPeerEndpointHelper.TryParse(peerEndpoint, out var parsed))
                {
                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogWarning($"Invalid {peerEndpoint}.");
                    }

                    continue;
                }

                // check that we haven't already reconnected to this node
                if (_peerPool.FindPeerByEndpoint(parsed) != null)
                {
                    Logger.LogDebug($"Peer {peerEndpoint} already in the pool, no need to reconnect.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find to {peerEndpoint}.");
                    }

                    continue;
                }

                Logger.LogDebug($"Starting reconnection to {peerToConnect.Endpoint}.");

                var connected = false;

                try
                {
                    connected = await _networkService.AddPeerAsync(peerEndpoint);
                }
                catch (Exception ex)
                {
                    // down the stack the AddPeerAsync rethrows any exception,
                    // in order to continue this job, Exception has to be catched for now.
                    Logger.LogError(ex, $"Could not re-connect to {peerEndpoint}.");
                }

                if (connected)
                {
                    Logger.LogDebug($"Reconnection to {peerEndpoint} succeeded.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find {peerEndpoint}.");
                    }
                }
                else
                {
                    peerToConnect.NextAttempt =
                        TimestampHelper.GetUtcNow().AddMilliseconds(_networkOptions.PeerReconnectionPeriod);

                    Logger.LogDebug($"Could not connect to {peerEndpoint}, next attempt {peerToConnect.NextAttempt}.");
                }
            }

            void CheckNtpClockDrift()
            {
                try
                {
                    _networkService.CheckNtpDrift();
                }
                catch (Exception)
                {
                    // swallow any exception, we are not interested in anything else than valid checks.
                }
            }
        }
        internal async Task DoReconnectionJobAsync()
        {
            await _networkService.SendHealthChecksAsync();

            var peersToConnect = _reconnectionService.GetPeersReadyForReconnection(TimestampHelper.GetUtcNow());

            if (peersToConnect.Count <= 0)
            {
                Logger.LogDebug("No peers to reconnect.");
                return;
            }

            foreach (var peerToConnect in peersToConnect)
            {
                string peerEndpoint = peerToConnect.Endpoint;

                // check that we haven't already reconnected to this node
                if (_peerPool.FindPeerByEndpoint(IpEndPointHelper.Parse(peerEndpoint)) != null)
                {
                    Logger.LogDebug($"Peer {peerEndpoint} already in the pool, no need to reconnect.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find to {peerEndpoint}.");
                    }

                    continue;
                }

                Logger.LogDebug($"Starting reconnection to {peerToConnect.Endpoint}.");

                var connected = false;

                try
                {
                    connected = await _networkService.AddPeerAsync(peerEndpoint);
                }
                catch (Exception ex)
                {
                    // todo consider different handling of the exception in dialer
                    // down the stack the AddPeerAsync rethrows any exception,
                    // in order to continue this job, Exception has to be catched for now.
                    Logger.LogError(ex, $"Could not re-connect to {peerEndpoint}.");
                }

                if (connected)
                {
                    Logger.LogDebug($"Reconnection to {peerEndpoint} succeeded.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find {peerEndpoint}.");
                    }
                }
                else
                {
                    peerToConnect.NextAttempt =
                        TimestampHelper.GetUtcNow().AddMilliseconds(_networkOptions.PeerReconnectionPeriod);

                    Logger.LogDebug($"Could not connect to {peerEndpoint}, next attempt {peerToConnect.NextAttempt}.");
                }
            }
        }