Example #1
0
        /// <summary>
        /// First step of the connect/auth process. Used to initiate a connection. The provided payload should be the
        /// clients authentication information. When receiving this call, protocol dictates you send the client your auth
        /// information. The response says whether or not you can connect.
        /// </summary>
        public override async Task <ConnectReply> Connect(Handshake handshake, ServerCallContext context)
        {
            Logger.LogTrace($"{context.Peer} has initiated a connection request.");

            if (handshake?.HskData == null)
            {
                return new ConnectReply {
                           Err = AuthError.InvalidHandshake
                }
            }
            ;

            // verify chain id
            if (handshake.HskData.ChainId != _blockChainService.GetChainId())
            {
                return new ConnectReply {
                           Err = AuthError.ChainMismatch
                }
            }
            ;

            // verify protocol
            if (handshake.HskData.Version != KernelConstants.ProtocolVersion)
            {
                return new ConnectReply {
                           Err = AuthError.ProtocolMismatch
                }
            }
            ;

            // verify signature
            var validData = await _accountService.VerifySignatureAsync(handshake.Sig.ToByteArray(),
                                                                       Hash.FromMessage(handshake.HskData).ToByteArray(), handshake.HskData.PublicKey.ToByteArray());

            if (!validData)
            {
                return new ConnectReply {
                           Err = AuthError.WrongSig
                }
            }
            ;

            var peer = GrpcUrl.Parse(context.Peer);

            if (peer == null)
            {
                return new ConnectReply {
                           Err = AuthError.InvalidPeer
                }
            }
            ;

            var peerAddress = peer.IpAddress + ":" + handshake.HskData.ListeningPort;

            Logger.LogDebug($"Attempting to create channel to {peerAddress}");

            Channel channel = new Channel(peerAddress, ChannelCredentials.Insecure);
            var     client  = new PeerService.PeerServiceClient(channel.Intercept(metadata =>
            {
                metadata.Add(GrpcConsts.PubkeyMetadataKey, AsyncHelper.RunSync(() => _accountService.GetPublicKeyAsync()).ToHex());
                return(metadata);
            }));

            if (channel.State != ChannelState.Ready)
            {
                var c = channel.WaitForStateChangedAsync(channel.State);
            }

            var pubKey   = handshake.HskData.PublicKey.ToHex();
            var grpcPeer = new GrpcPeer(channel, client, pubKey, peerAddress);

            // Verify auth
            bool valid = _peerPool.IsAuthenticatePeer(pubKey);

            if (!valid)
            {
                await channel.ShutdownAsync();

                Logger.LogDebug($"Failed to reach {grpcPeer}");
                return(new ConnectReply {
                    Err = AuthError.WrongAuth
                });
            }

            // send our credentials
            var hsk = await _peerPool.GetHandshakeAsync();

            // If auth ok -> add it to our peers
            _peerPool.AddPeer(grpcPeer);

            return(new ConnectReply {
                Handshake = hsk
            });
        }