Пример #1
0
        public Task SendGetHeaders(Peer peer)
        {
            if (!IsStarted)
                return Task.CompletedTask;

            var targetChainLocal = this.coreDaemon.TargetChain;
            if (targetChainLocal == null)
                return Task.CompletedTask;

            var blockLocatorHashes = CalculateBlockLocatorHashes(targetChainLocal.Blocks);

            // remove an existing request for this peer if it's stale
            var now = DateTimeOffset.Now;
            DateTimeOffset requestTime;
            if (this.headersRequestsByPeer.TryGetValue(peer, out requestTime)
                && (now - requestTime) > STALE_REQUEST_TIME)
            {
                this.headersRequestsByPeer.TryRemove(peer, out requestTime);
            }

            // determine if a new request can be made
            if (this.headersRequestsByPeer.TryAdd(peer, now))
                // send out the request for headers
                return peer.Sender.SendGetHeaders(blockLocatorHashes, hashStop: UInt256.Zero);
            else
                return Task.CompletedTask;
        }
Пример #2
0
 public void AddIncomingPeer(Socket socket)
 {
     var peer = new Peer(socket, isSeed: false);
     try
     {
         ConnectAndHandshake(peer, isIncoming: true)
             .ContinueWith(task => DisconnectPeer(peer, task.Exception), TaskContinuationOptions.OnlyOnFaulted)
             .Forget();
     }
     catch (Exception e)
     {
         DisconnectPeer(peer, e);
         throw;
     }
 }
Пример #3
0
        public async Task AddIncomingPeer(Socket socket)
        {
            var peer = new Peer(socket, isSeed: false, isIncoming: true);
            try
            {
                await ConnectAndHandshake(peer);

                PeerHandshakeCompleted?.Invoke(peer);

                this.pendingPeers.TryRemove(peer);
                this.connectedPeers.TryAdd(peer);
            }
            catch (Exception e)
            {
                DisconnectPeer(peer, e);
                throw;
            }
        }
Пример #4
0
 public FlushHeaders(Peer peer, IImmutableList<BlockHeader> headers)
 {
     Peer = peer;
     Headers = headers;
 }
Пример #5
0
 private void HandleBlockHeaders(Peer peer, IImmutableList<BlockHeader> blockHeaders)
 {
     if (blockHeaders.Count > 0)
     {
         this.flushQueue.Enqueue(new FlushHeaders(peer, blockHeaders));
         this.flushWorker.NotifyWork();
     }
     else
     {
         DateTimeOffset ignore;
         this.headersRequestsByPeer.TryRemove(peer, out ignore);
     }
 }
Пример #6
0
        public void DisconnectPeer(Peer peer, Exception ex)
        {
            if (ex != null)
                logger.Debug(ex, $"Remote peer failed: {peer.RemoteEndPoint}");

            PeerDisconnected?.Invoke(peer);

            if (peer.IsIncoming)
                Interlocked.Decrement(ref this.incomingCount);

            this.badPeers.Add(peer.RemoteEndPoint); //TODO

            this.unconnectedPeersLock.Do(() =>
                this.unconnectedPeers.Remove(peer.RemoteEndPoint));
            this.pendingPeers.TryRemove(peer);
            this.connectedPeers.TryRemove(peer);

            peer.OnDisconnect -= DisconnectPeer;
            peer.Dispose();
        }
Пример #7
0
 private async Task PeerStartup(Peer peer)
 {
     await peer.Sender.RequestKnownAddressesAsync();
     await headersRequestWorker.SendGetHeaders(peer);
 }
Пример #8
0
        private async Task ConnectAndHandshake(Peer peer)
        {
            peer.OnDisconnect += DisconnectPeer;
            if (peer.IsIncoming)
                Interlocked.Increment(ref this.incomingCount);

            // connect
            await peer.ConnectAsync();

            // notify peer is connected
            PeerConnected?.Invoke(peer);

            // setup task to wait for verack
            var verAckTask = peer.Receiver.WaitForMessage(x => x.Command == "verack", HANDSHAKE_TIMEOUT_MS);

            // setup task to wait for version
            var versionTask = peer.Receiver.WaitForMessage(x => x.Command == "version", HANDSHAKE_TIMEOUT_MS);

            // start listening for messages after tasks have been setup
            peer.Receiver.Listen();

            // send our local version
            var nodeId = random.NextUInt64(); //TODO should be generated and verified on version message

            var currentHeight = this.coreDaemon.CurrentChain.Height;
            await peer.Sender.SendVersion(Messaging.GetExternalIPEndPoint(), peer.RemoteEndPoint, nodeId, (UInt32)currentHeight);

            // wait for our local version to be acknowledged by the remote peer
            // wait for remote peer to send their version
            await Task.WhenAll(verAckTask, versionTask);

            //TODO shouldn't have to decode again
            var versionMessage = versionTask.Result;
            var versionPayload = NodeEncoder.DecodeVersionPayload(versionMessage.Payload.ToArray(), versionMessage.Payload.Length);

            var remoteAddressWithTime = new NetworkAddressWithTime
            (
                Time: DateTimeOffset.Now,
                NetworkAddress: new NetworkAddress
                (
                    Services: versionPayload.LocalAddress.Services,
                    IPv6Address: versionPayload.LocalAddress.IPv6Address,
                    Port: versionPayload.LocalAddress.Port
                )
            );

            // acknowledge their version
            await peer.Sender.SendVersionAcknowledge();
        }
Пример #9
0
 private async Task PeerStartup(Peer peer)
 {
     await peer.Sender.RequestKnownAddressesAsync();
 }
Пример #10
0
 public RemoteSender(Peer owner, Socket socket)
 {
     this.owner = owner;
     this.socket = socket;
 }
Пример #11
0
 public RemoteReceiver(Peer owner, Socket socket, bool persistent)
 {
     this.owner = owner;
     this.socket = socket;
     this.persistent = persistent;
 }
Пример #12
0
        public void DisconnectPeer(Peer peer, Exception ex)
        {
            if (ex != null)
                logger.Debug(ex, $"Remote peer failed: {peer.RemoteEndPoint}");

            RaisePeerDisconnected(peer);

            this.badPeers.Add(peer.RemoteEndPoint); //TODO

            this.unconnectedPeersLock.Do(() =>
                this.unconnectedPeers.Remove(peer.RemoteEndPoint));
            this.pendingPeers.TryRemove(peer);
            this.connectedPeers.TryRemove(peer);

            peer.OnDisconnect -= DisconnectPeer;
            peer.Dispose();
        }
Пример #13
0
 //TODO if a peer is in use on another thread, it could get disconnected here
 //TODO e.g. slow peers are detected and disconnected separately from the block requester using them
 public void DisconnectPeer(Peer peer)
 {
     DisconnectPeer(peer, null);
 }
Пример #14
0
 private void RaisePeerDisconnected(Peer peer)
 {
     this.PeerDisconnected?.Invoke(peer);
 }
Пример #15
0
        private async Task<Peer> ConnectToPeer(IPEndPoint remoteEndPoint, bool isSeed)
        {
            try
            {
                var peer = new Peer(remoteEndPoint, isSeed, isIncoming: false);
                try
                {
                    this.unconnectedPeersLock.Do(() =>
                        this.unconnectedPeers.Remove(remoteEndPoint));
                    this.pendingPeers.TryAdd(peer);

                    await ConnectAndHandshake(peer);
                    await PeerStartup(peer);

                    PeerHandshakeCompleted?.Invoke(peer);

                    this.pendingPeers.TryRemove(peer);
                    this.connectedPeers.TryAdd(peer);

                    return peer;
                }
                catch (Exception ex)
                {
                    logger.Debug(ex, $"Could not connect to {remoteEndPoint}");
                    DisconnectPeer(peer, ex);
                    return null;
                }
            }
            catch (Exception)
            {
                this.badPeers.Add(remoteEndPoint); //TODO
                this.unconnectedPeersLock.Do(() =>
                    this.unconnectedPeers.Remove(remoteEndPoint));
                throw;
            }
        }
Пример #16
0
 public RemoteReceiver(Peer owner, Socket socket)
 {
     this.owner = owner;
     this.socket = socket;
 }
Пример #17
0
        private void HandleFailed(Peer peer, Exception ex)
        {
            if (ex != null)
                logger.Debug(ex, $"Remote peer failed: {this.RemoteEndPoint}");
            else
                logger.Debug($"Remote peer failed: {this.RemoteEndPoint}");

            Disconnect(ex);
        }