Exemple #1
0
        /// <summary>
        /// Sends "version" message to the peer and waits for the response in form of "verack" or "reject" message.
        /// </summary>
        /// <param name="cancellationToken">Cancellation that allows aborting the operation at any stage.</param>
        /// <exception cref="ProtocolException">Thrown when the peer rejected our "version" message.</exception>
        public async Task RespondToHandShakeAsync(CancellationToken cancellation = default(CancellationToken))
        {
            this.logger.LogTrace("()");

            using (var listener = new NetworkPeerListener(this).Where(m => (m.Message.Payload is VerAckPayload) || (m.Message.Payload is RejectPayload)))
            {
                this.logger.LogTrace("Responding to handshake with my version.");
                await this.SendMessageAsync(this.MyVersion);

                this.logger.LogTrace("Waiting for version acknowledgement or rejection message.");
                IncomingMessage message = listener.ReceiveMessage(cancellation);

                if (message.Message.Payload is RejectPayload reject)
                {
                    this.logger.LogTrace("Version rejected: code {0}, reason '{1}'.", reject.Code, reject.Reason);
                    this.logger.LogTrace("(-)[VERSION_REJECTED]");
                    throw new ProtocolException("Version rejected " + reject.Code + ": " + reject.Reason);
                }

                this.logger.LogTrace("Sending version acknowledgement.");
                await this.SendMessageAsync(new VerAckPayload());

                this.State = NetworkPeerState.HandShaked;
            }

            this.logger.LogTrace("(-)");
        }
Exemple #2
0
        /// <summary>
        /// Waits for a message of specific type to be received from the peer.
        /// </summary>
        /// <typeparam name="TPayload">Type of message to wait for.</typeparam>
        /// <param name="cancellationToken">Cancellation that allows aborting the operation.</param>
        /// <returns>Received message.</returns>
        /// <exception cref="OperationCanceledException">Thrown if the cancellation token was cancelled.</exception>
        public TPayload ReceiveMessage <TPayload>(CancellationToken cancellationToken = default(CancellationToken)) where TPayload : Payload
        {
            this.logger.LogTrace("()");

            using (var listener = new NetworkPeerListener(this))
            {
                TPayload res = listener.ReceivePayload <TPayload>(cancellationToken);

                this.logger.LogTrace("(-):'{0}'", res);
                return(res);
            }
        }
Exemple #3
0
        /// <summary>
        /// Exchanges "version" and "verack" messages with the peer.
        /// <para>Both parties have to send their "version" messages to the other party
        /// as well as to acknowledge that they are happy with the other party's "version" information.</para>
        /// </summary>
        /// <param name="requirements">Protocol requirement for network peers the node wants to be connected to.</param>
        /// <param name="cancellationToken">Cancellation that allows aborting the operation at any stage.</param>
        public async Task VersionHandshakeAsync(NetworkPeerRequirement requirements, CancellationToken cancellationToken)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(requirements), nameof(requirements.RequiredServices), requirements?.RequiredServices);

            requirements = requirements ?? new NetworkPeerRequirement();
            using (var listener = new NetworkPeerListener(this).Where(p => (p.Message.Payload is VersionPayload) ||
                                                                      (p.Message.Payload is RejectPayload) ||
                                                                      (p.Message.Payload is VerAckPayload)))
            {
                this.logger.LogTrace("Sending my version.");
                await this.SendMessageAsync(this.MyVersion).ConfigureAwait(false);

                this.logger.LogTrace("Waiting for version or rejection message.");
                Payload payload = listener.ReceivePayload <Payload>(cancellationToken);
                if (payload is RejectPayload)
                {
                    this.logger.LogTrace("(-)[HANDSHAKE_REJECTED]");
                    throw new ProtocolException("Handshake rejected: " + ((RejectPayload)payload).Reason);
                }

                var version = (VersionPayload)payload;
                this.PeerVersion = version;
                if (!version.AddressReceiver.Address.Equals(this.MyVersion.AddressFrom.Address))
                {
                    this.logger.LogDebug("Different external address detected by the node '{0}' instead of '{1}'.", version.AddressReceiver.Address, this.MyVersion.AddressFrom.Address);
                }

                if (version.Version < ProtocolVersion.MIN_PEER_PROTO_VERSION)
                {
                    this.logger.LogDebug("Outdated version {0} received, disconnecting peer.", version.Version);

                    this.Disconnect("Outdated version");
                    this.logger.LogTrace("(-)[OUTDATED]");
                    return;
                }

                if (!requirements.Check(version))
                {
                    this.logger.LogTrace("(-)[UNSUPPORTED_REQUIREMENTS]");
                    this.Disconnect("The peer does not support the required services requirement");
                    return;
                }

                this.logger.LogTrace("Sending version acknowledgement.");
                await this.SendMessageAsync(new VerAckPayload()).ConfigureAwait(false);

                this.logger.LogTrace("Waiting for version acknowledgement.");
                listener.ReceivePayload <VerAckPayload>(cancellationToken);
                this.State = NetworkPeerState.HandShaked;

                if (this.Advertize && this.MyVersion.AddressFrom.Address.IsRoutable(true))
                {
                    this.SendMessageVoidAsync(new AddrPayload(new NetworkAddress(this.MyVersion.AddressFrom)
                    {
                        Time = this.dateTimeProvider.GetTimeOffset()
                    }));
                }
            }

            this.logger.LogTrace("(-)");
        }