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; }
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; } }
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; } }
public FlushHeaders(Peer peer, IImmutableList<BlockHeader> headers) { Peer = peer; Headers = headers; }
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); } }
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(); }
private async Task PeerStartup(Peer peer) { await peer.Sender.RequestKnownAddressesAsync(); await headersRequestWorker.SendGetHeaders(peer); }
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(); }
private async Task PeerStartup(Peer peer) { await peer.Sender.RequestKnownAddressesAsync(); }
public RemoteSender(Peer owner, Socket socket) { this.owner = owner; this.socket = socket; }
public RemoteReceiver(Peer owner, Socket socket, bool persistent) { this.owner = owner; this.socket = socket; this.persistent = persistent; }
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(); }
//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); }
private void RaisePeerDisconnected(Peer peer) { this.PeerDisconnected?.Invoke(peer); }
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; } }
public RemoteReceiver(Peer owner, Socket socket) { this.owner = owner; this.socket = socket; }
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); }