/// <inheritdoc/> public async Task RespondToHandShakeAsync(CancellationToken cancellationToken = default(CancellationToken)) { this.logger.LogTrace("()"); using (var listener = new NetworkPeerListener(this)) { this.logger.LogTrace("Responding to handshake with my version."); await this.SendMessageAsync(this.MyVersion, cancellationToken).ConfigureAwait(false); this.logger.LogTrace("Waiting for version acknowledgement or rejection message."); while (this.State != NetworkPeerState.HandShaked) { Payload payload = await listener.ReceivePayloadAsync <Payload>(cancellationToken).ConfigureAwait(false); switch (payload) { case RejectPayload rejectPayload: this.logger.LogTrace("Version rejected: code {0}, reason '{1}'.", rejectPayload.Code, rejectPayload.Reason); this.logger.LogTrace("(-)[VERSION_REJECTED]"); throw new ProtocolException("Version rejected " + rejectPayload.Code + ": " + rejectPayload.Reason); case VerAckPayload verAckPayload: this.logger.LogTrace("Sending version acknowledgement."); await this.SendMessageAsync(new VerAckPayload(), cancellationToken).ConfigureAwait(false); await this.SetStateAsync(NetworkPeerState.HandShaked).ConfigureAwait(false); break; } } } this.logger.LogTrace("(-)"); }
/// <inheritdoc/> 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)) { this.logger.LogTrace("Sending my version."); await this.SendMessageAsync(this.MyVersion, cancellationToken).ConfigureAwait(false); this.logger.LogTrace("Waiting for version or rejection message."); bool versionReceived = false; bool verAckReceived = false; while (!versionReceived || !verAckReceived) { Payload payload = await listener.ReceivePayloadAsync <Payload>(cancellationToken).ConfigureAwait(false); switch (payload) { case RejectPayload rejectPayload: this.logger.LogTrace("(-)[HANDSHAKE_REJECTED]"); throw new ProtocolException("Handshake rejected: " + rejectPayload.Reason); case VersionPayload versionPayload: versionReceived = true; this.PeerVersion = versionPayload; if (!versionPayload.AddressReceiver.Address.Equals(this.MyVersion.AddressFrom.Address)) { this.logger.LogDebug("Different external address detected by the node '{0}' instead of '{1}'.", versionPayload.AddressReceiver.Address, this.MyVersion.AddressFrom.Address); } if (versionPayload.Version < ProtocolVersion.MIN_PEER_PROTO_VERSION) { this.logger.LogDebug("Outdated version {0} received, disconnecting peer.", versionPayload.Version); this.Disconnect("Outdated version"); this.logger.LogTrace("(-)[OUTDATED]"); return; } if (!requirements.Check(versionPayload)) { 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(), cancellationToken).ConfigureAwait(false); break; case VerAckPayload verAckPayload: verAckReceived = true; break; } } await this.SetStateAsync(NetworkPeerState.HandShaked).ConfigureAwait(false); if (this.advertize && this.MyVersion.AddressFrom.Address.IsRoutable(true)) { var addrPayload = new AddrPayload ( new NetworkAddress(this.MyVersion.AddressFrom) { Time = this.dateTimeProvider.GetTimeOffset() } ); await this.SendMessageAsync(addrPayload, cancellationToken).ConfigureAwait(false); } } this.logger.LogTrace("(-)"); }