Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
            }
        }