public async Task <(IRemoteNode, VersionPayload)> ConnectAsync(IPEndPoint endPoint, uint nonce, uint startHeight, CancellationToken token = default) { var pipelineSocket = provider.GetRequiredService <IPipelineSocket>(); var networkOptions = provider.GetRequiredService <IOptions <NetworkOptions> >(); var nodeOptions = provider.GetRequiredService <IOptions <NodeOptions> >(); var logger = provider.GetService <ILogger <RemoteNode> >(); var node = new RemoteNode(pipelineSocket, networkOptions, nodeOptions, logger); var remoteVersion = await node.ConnectAsync(endPoint, nonce, startHeight, token); return(node, remoteVersion); }
private async Task <bool> ConnectAndHandshake(RemoteNode remoteNode, bool isIncoming) { // wire node WireNode(remoteNode); // connect await remoteNode.ConnectAsync(); if (remoteNode.IsConnected) { //TODO RemoteNode ignore; this.pendingPeers.TryRemove(remoteNode.RemoteEndPoint, out ignore); this.connectedPeers.TryAdd(remoteNode.RemoteEndPoint, remoteNode); // setup task to wait for verack var verAckTask = remoteNode.Receiver.WaitForMessage(x => x.Command == "verack", HANDSHAKE_TIMEOUT_MS); // setup task to wait for version var versionTask = remoteNode.Receiver.WaitForMessage(x => x.Command == "version", HANDSHAKE_TIMEOUT_MS); // start listening for messages after tasks have been setup remoteNode.Receiver.Listen(); // send our local version var nodeId = random.NextUInt64(); //TODO should be generated and verified on version message var currentHeight = this.blockchainDaemon.CurrentChain.Height; await remoteNode.Sender.SendVersion(Messaging.GetExternalIPEndPoint(), remoteNode.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.Count); var remoteAddressWithTime = new NetworkAddressWithTime ( Time: DateTime.UtcNow.ToUnixTime(), NetworkAddress: new NetworkAddress ( Services: versionPayload.LocalAddress.Services, IPv6Address: versionPayload.LocalAddress.IPv6Address, Port: versionPayload.LocalAddress.Port ) ); if (!isIncoming) { this.networkPeerCache[remoteAddressWithTime.GetKey()] = remoteAddressWithTime; } // acknowledge their version await remoteNode.Sender.SendVersionAcknowledge(); this.headersRequestWorker.NotifyWork(); this.blockRequestWorker.NotifyWork(); this.statsWorker.NotifyWork(); return(true); } else { return(false); } }