public async Task DialBackPeer_Test() { AElfPeerEndpointHelper.TryParse("127.0.0.1:2000", out var endpoint); var handshake = await _handshakeProvider.GetHandshakeAsync(); var grpcPeer = await _peerDialer.DialBackPeerAsync(endpoint, handshake); grpcPeer.ShouldNotBeNull(); grpcPeer.CurrentBlockHash.ShouldBe(handshake.HandshakeData.BestChainHash); grpcPeer.CurrentBlockHeight.ShouldBe(handshake.HandshakeData.BestChainHeight); grpcPeer.LastKnownLibHeight.ShouldBe(handshake.HandshakeData.LastIrreversibleBlockHeight); grpcPeer.Info.Pubkey.ShouldBe(handshake.HandshakeData.Pubkey.ToHex()); grpcPeer.Info.ProtocolVersion.ShouldBe(handshake.HandshakeData.Version); }
public async Task GetHandshakeAsync_Test() { var handshake = await _handshakeProvider.GetHandshakeAsync(); handshake.ShouldNotBeNull(); handshake.HandshakeData.Pubkey.ShouldBe(await _accountService.GetPublicKeyAsync()); }
public async Task ValidateHandshake_Test() { var remoteKeyPair = _peerKeyProvider.AuthorizedKey; var handshake = CreateHandshake(remoteKeyPair); var validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.Ok); handshake = CreateHandshake(remoteKeyPair); var unauthorizedKeyPair = CryptoHelper.GenerateKeyPair(); handshake.HandshakeData.Pubkey = ByteString.CopyFrom(unauthorizedKeyPair.PublicKey); validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.Unauthorized); handshake = CreateHandshake(remoteKeyPair); handshake.HandshakeData.ChainId = 1234; validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.InvalidChainId); handshake = CreateHandshake(remoteKeyPair); handshake.HandshakeData.Version = 0; validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.InvalidVersion); handshake = CreateHandshake(remoteKeyPair); handshake.HandshakeData.Time = TimestampHelper.GetUtcNow().AddMilliseconds(-(NetworkConstants.HandshakeTimeout + 100)); validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.HandshakeTimeout); handshake = CreateHandshake(remoteKeyPair); var maliciousPeer = CryptoHelper.GenerateKeyPair(); var signature = CryptoHelper.SignWithPrivateKey(maliciousPeer.PrivateKey, Hash .FromMessage(handshake.HandshakeData) .ToByteArray()); handshake.Signature = ByteString.CopyFrom(signature); validationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); validationResult.ShouldBe(HandshakeValidationResult.InvalidSignature); var localHandshake = await _handshakeProvider.GetHandshakeAsync(); validationResult = await _handshakeProvider.ValidateHandshakeAsync(localHandshake); validationResult.ShouldBe(HandshakeValidationResult.SelfConnection); }
/// <summary> /// Given an IP address, will create a handshake to the distant node for /// further communications. /// </summary> /// <returns>The created peer</returns> public async Task <GrpcPeer> DialPeerAsync(DnsEndPoint remoteEndpoint) { var client = await CreateClientAsync(remoteEndpoint); if (client == null) { return(null); } var handshake = await _handshakeProvider.GetHandshakeAsync(); var handshakeReply = await CallDoHandshakeAsync(client, remoteEndpoint, handshake); // verify handshake if (handshakeReply.Error != HandshakeError.HandshakeOk) { Logger.LogWarning($"Handshake error: {remoteEndpoint} {handshakeReply.Error}."); await client.Channel.ShutdownAsync(); return(null); } if (await _handshakeProvider.ValidateHandshakeAsync(handshakeReply.Handshake) != HandshakeValidationResult.Ok) { Logger.LogWarning($"Connect error: {remoteEndpoint} {handshakeReply}."); await client.Channel.ShutdownAsync(); return(null); } var peer = new GrpcPeer(client, remoteEndpoint, new PeerConnectionInfo { Pubkey = handshakeReply.Handshake.HandshakeData.Pubkey.ToHex(), ConnectionTime = TimestampHelper.GetUtcNow(), ProtocolVersion = handshakeReply.Handshake.HandshakeData.Version, SessionId = handshakeReply.Handshake.SessionId.ToByteArray(), IsInbound = false }); peer.UpdateLastReceivedHandshake(handshakeReply.Handshake); peer.InboundSessionId = handshake.SessionId.ToByteArray(); peer.UpdateLastSentHandshake(handshake); return(peer); }
/// <summary> /// Updates the current target for the initial sync. For now this method will /// not have any effect if the sync is already finished or the target has not /// been initialized. /// </summary> /// <returns></returns> public async Task UpdateSyncStateAsync() { // This method should only be called when the sync target has already been found and the // node is syncing. if (SyncState != SyncState.Syncing) { Logger.LogWarning("Trying to update the sync, but it is either finished or not yet been initialized."); return; } var chain = await _blockchainService.GetChainAsync(); // if the current LIB is higher than the recorded target, update // the peers current LIB height. Note that this condition will // also be true when the node starts. if (chain.LastIrreversibleBlockHeight >= _syncStateProvider.SyncTarget) { var handshake = await _handshakeProvider.GetHandshakeAsync(); // Update handshake information of all our peers var tasks = _peerPool.GetPeers().Select(async peer => { try { await peer.DoHandshakeAsync(handshake); } catch (NetworkException e) { Logger.LogError(e, "Error while handshaking."); } Logger.LogDebug($"Peer {peer} last known LIB is {peer.LastKnownLibHeight}."); }).ToList(); await Task.WhenAll(tasks); await UpdateSyncTargetAsync(); } }
public async Task DoHandshake_InvalidHandshake_Test() { AElfPeerEndpointHelper.TryParse(NetworkTestConstants.GoodPeerEndpoint, out var endpoint); var handshake = CreateHandshake(); handshake.HandshakeData.ChainId = 100; var result = await _connectionService.DoHandshakeAsync(endpoint, handshake); result.Error.ShouldBe(HandshakeError.ChainMismatch); handshake = CreateHandshake(); handshake.HandshakeData.Version = 100; result = await _connectionService.DoHandshakeAsync(endpoint, handshake); result.Error.ShouldBe(HandshakeError.ProtocolMismatch); handshake = CreateHandshake(); handshake.HandshakeData.Time = handshake.HandshakeData.Time - TimestampHelper.DurationFromMilliseconds( NetworkConstants.HandshakeTimeout + 1000); result = await _connectionService.DoHandshakeAsync(endpoint, handshake); result.Error.ShouldBe(HandshakeError.SignatureTimeout); handshake = CreateHandshake(); handshake.HandshakeData.Pubkey = ByteString.CopyFrom(CryptoHelper.GenerateKeyPair().PublicKey); result = await _connectionService.DoHandshakeAsync(endpoint, handshake); result.Error.ShouldBe(HandshakeError.WrongSignature); handshake = await _handshakeProvider.GetHandshakeAsync(); result = await _connectionService.DoHandshakeAsync(endpoint, handshake); result.Error.ShouldBe(HandshakeError.ConnectionRefused); }
public async Task <HandshakeReply> DoHandshakeAsync(DnsEndPoint endpoint, Handshake handshake) { // validate the handshake (signature, chain id...) var handshakeValidationResult = await _handshakeProvider.ValidateHandshakeAsync(handshake); if (handshakeValidationResult != HandshakeValidationResult.Ok) { var handshakeError = GetHandshakeError(handshakeValidationResult); return(new HandshakeReply { Error = handshakeError }); } var pubkey = handshake.HandshakeData.Pubkey.ToHex(); // remove any remaining connection to the peer (before the check // that we have room for more connections) var currentPeer = _peerPool.FindPeerByPublicKey(pubkey); if (currentPeer != null) { _peerPool.RemovePeer(pubkey); await currentPeer.DisconnectAsync(false); } try { // mark the (IP; pubkey) pair as currently handshaking if (!_peerPool.AddHandshakingPeer(endpoint.Host, pubkey)) { return new HandshakeReply { Error = HandshakeError.ConnectionRefused } } ; // create the connection to the peer var peerEndpoint = new AElfPeerEndpoint(endpoint.Host, handshake.HandshakeData.ListeningPort); var grpcPeer = await _peerDialer.DialBackPeerAsync(peerEndpoint, handshake); // add the new peer to the pool if (!_peerPool.TryAddPeer(grpcPeer)) { Logger.LogWarning($"Stopping connection, peer already in the pool {grpcPeer.Info.Pubkey}."); await grpcPeer.DisconnectAsync(false); return(new HandshakeReply { Error = HandshakeError.RepeatedConnection }); } Logger.LogDebug($"Added to pool {grpcPeer.RemoteEndpoint} - {grpcPeer.Info.Pubkey}."); // send back our handshake var replyHandshake = await _handshakeProvider.GetHandshakeAsync(); grpcPeer.InboundSessionId = replyHandshake.SessionId.ToByteArray(); grpcPeer.UpdateLastSentHandshake(replyHandshake); return(new HandshakeReply { Handshake = replyHandshake, Error = HandshakeError.HandshakeOk }); } finally { // remove the handshaking mark (IP; pubkey) _peerPool.RemoveHandshakingPeer(endpoint.Host, pubkey); } }
/// <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); }