示例#1
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 = (((UInt64)random.Next()) << 32) + (UInt64)random.Next(); //TODO should be generated and verified on version message

                var currentBlockchainLocal = this.blockchainDaemon.CurrentBlockchain;
                var currentHeight = !currentBlockchainLocal.IsDefault ? (UInt32)currentBlockchainLocal.Height : 0;
                await remoteNode.Sender.SendVersion(Messaging.GetExternalIPEndPoint(), remoteNode.RemoteEndPoint, nodeId, 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 = NetworkEncoder.DecodeVersionPayload(versionMessage.Payload.ToArray().ToMemoryStream(), versionMessage.Payload.Length);

                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.knownAddressCache.UpdateValue(remoteAddressWithTime.GetKey(), remoteAddressWithTime);

                // acknowledge their version
                await remoteNode.Sender.SendVersionAcknowledge();

                return true;
            }
            else
            {
                return false;
            }
        }
示例#2
0
 private void OnPing(RemoteNode remoteNode, ImmutableArray<byte> payload)
 {
     remoteNode.Sender.SendMessageAsync(Messaging.ConstructMessage("pong", payload.ToArray())).Wait();
 }
示例#3
0
 private void OnDisconnect(RemoteNode remoteNode)
 {
     DisconnectPeer(remoteNode.RemoteEndPoint, null);
 }
示例#4
0
 private void OnGetBlocks(RemoteNode remoteNode, GetBlocksPayload payload)
 {
     //TODO
 }
示例#5
0
        private void OnGetHeaders(RemoteNode remoteNode, GetBlocksPayload payload)
        {
            // if in comparison mode, synchronize all work before returning current headers
            if (this.Type == LocalClientType.ComparisonToolTestNet)
                this.blockchainDaemon.WaitForFullUpdate();

            var currentBlockchainLocal = this.blockchainDaemon.CurrentBlockchain;
            var blockHeaders = new List<BlockHeader>(currentBlockchainLocal.BlockCount);
            foreach (var chainedBlock in currentBlockchainLocal.BlockList)
            {
                BlockHeader blockHeader;
                if (this.blockchainDaemon.CacheContext.BlockHeaderCache.TryGetValue(chainedBlock.BlockHash, out blockHeader))
                {
                    blockHeaders.Add(blockHeader);
                }
                else
                {
                    Debugger.Break();
                    Debug.WriteLine("Couldn't generate getheaders response");
                    return;
                }
            }

            var payloadStream = new MemoryStream();
            using (var payloadWriter = new BinaryWriter(payloadStream))
            {
                payloadWriter.WriteVarInt((UInt64)blockHeaders.Count);
                foreach (var blockHeader in blockHeaders)
                {
                    NetworkEncoder.EncodeBlockHeader(payloadStream, blockHeader);
                    payloadWriter.WriteVarInt(0);
                }
            }

            remoteNode.Sender.SendMessageAsync(Messaging.ConstructMessage("headers", payloadStream.ToArray())).Wait();
        }
示例#6
0
 private void UnwireNode(RemoteNode remoteNode)
 {
     remoteNode.Receiver.OnMessage -= OnMessage;
     remoteNode.Receiver.OnInventoryVectors -= OnInventoryVectors;
     remoteNode.Receiver.OnBlock -= OnBlock;
     remoteNode.Receiver.OnBlockHeader -= OnBlockHeader;
     remoteNode.Receiver.OnReceivedAddresses -= OnReceivedAddresses;
     remoteNode.OnGetBlocks -= OnGetBlocks;
     remoteNode.OnGetHeaders -= OnGetHeaders;
     remoteNode.OnPing -= OnPing;
     remoteNode.OnDisconnect -= OnDisconnect;
 }
示例#7
0
        private Task RequestBlock(RemoteNode remoteNode, UInt256 blockHash)
        {
            if (this.blockchainDaemon.CacheContext.BlockCache.ContainsKey(blockHash))
                return null;

            var now = DateTime.UtcNow;
            var newRequestTime = Tuple.Create(now, (DateTime?)null);

            // check if block has already been requested
            if (this.requestedBlockTimes.TryAdd(blockHash, newRequestTime))
            {
                this.requestedBlocks.TryAdd(blockHash);
                var invVectors = ImmutableArray.Create<InventoryVector>(new InventoryVector(InventoryVector.TYPE_MESSAGE_BLOCK, blockHash));
                return remoteNode.Sender.SendGetData(invVectors);
            }
            else
            {
                // if block has already been requested, check if the request is old enough to send again
                Tuple<DateTime, DateTime?> lastRequestTime;
                if (this.requestedBlockTimes.TryGetValue(blockHash, out lastRequestTime))
                {
                    if ((now - lastRequestTime.Item1) > TimeSpan.FromSeconds(15))
                    {
                        this.requestedBlocks.TryAdd(blockHash);
                        this.requestedBlockTimes.AddOrUpdate(blockHash, newRequestTime, (existingKey, existingValue) => newRequestTime);

                        var invVectors = ImmutableArray.Create<InventoryVector>(new InventoryVector(InventoryVector.TYPE_MESSAGE_BLOCK, blockHash));
                        return remoteNode.Sender.SendGetData(invVectors);
                    }
                }
            }

            return null;
        }
示例#8
0
 private void WireNode(RemoteNode remoteNode)
 {
     remoteNode.Receiver.OnMessage += OnMessage;
     remoteNode.Receiver.OnInventoryVectors += OnInventoryVectors;
     remoteNode.Receiver.OnBlock += OnBlock;
     remoteNode.Receiver.OnBlockHeader += OnBlockHeader;
     remoteNode.Receiver.OnReceivedAddresses += OnReceivedAddresses;
     remoteNode.OnGetBlocks += OnGetBlocks;
     remoteNode.OnGetHeaders += OnGetHeaders;
     remoteNode.OnPing += OnPing;
     remoteNode.OnDisconnect += OnDisconnect;
 }
示例#9
0
        private async Task<RemoteNode> ConnectToPeer(IPEndPoint remoteEndPoint)
        {
            try
            {
                var remoteNode = new RemoteNode(remoteEndPoint);

                this.unconnectedPeers.TryRemove(remoteEndPoint);
                this.pendingPeers.TryAdd(remoteNode.RemoteEndPoint, remoteNode);

                var success = await ConnectAndHandshake(remoteNode, isIncoming: false);
                if (success)
                {
                    await PeerStartup(remoteNode);

                    return remoteNode;
                }
                else
                {
                    DisconnectPeer(remoteEndPoint, null);
                    return null;
                }
            }
            catch (Exception e)
            {
                //Debug.WriteLine(string.Format("Could not connect to {0}: {1}", remoteEndpoint, e.Message));
                DisconnectPeer(remoteEndPoint, e);
                return null;
            }
        }
示例#10
0
        private async Task SendGetBlocks(RemoteNode remoteNode)
        {
            var blockLocatorHashes = CalculateBlockLocatorHashes(this.blockchainDaemon.WinningBlockchain);

            await remoteNode.Sender.SendGetBlocks(blockLocatorHashes, hashStop: 0);
        }
示例#11
0
 private async Task PeerStartup(RemoteNode remoteNode)
 {
     await remoteNode.Sender.RequestKnownAddressesAsync();
 }
示例#12
0
        private async void StartListening()
        {
            switch (this.Type)
            {
                case LocalClientType.MainNet:
                case LocalClientType.TestNet3:
                    var externalIPAddress = Messaging.GetExternalIPAddress();
                    var localhost = Dns.GetHostEntry(Dns.GetHostName());

                    this.listenSocket = new Socket(externalIPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    this.listenSocket.Bind(new IPEndPoint(localhost.AddressList.Where(x => x.AddressFamily == externalIPAddress.AddressFamily).First(), Messaging.Port));
                    this.listenSocket.Listen(SERVER_BACKLOG);
                    break;

                case LocalClientType.ComparisonToolTestNet:
                    this.listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    this.listenSocket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), Messaging.Port));
                    this.listenSocket.Listen(SERVER_BACKLOG);
                    break;
            }

            try
            {
                while (true)
                {
                    // cooperative loop
                    this.shutdownToken.Token.ThrowIfCancellationRequested();

                    try
                    {
                        var newSocket = await Task.Factory.FromAsync<Socket>(this.listenSocket.BeginAccept(null, null), this.listenSocket.EndAccept);

                        Task.Run(async () =>
                        {
                            var remoteNode = new RemoteNode(newSocket);
                            try
                            {
                                if (await ConnectAndHandshake(remoteNode, isIncoming: true))
                                {
                                    Interlocked.Increment(ref this.incomingCount);
                                }
                                else
                                {
                                    DisconnectPeer(remoteNode.RemoteEndPoint, null);
                                }
                            }
                            catch (Exception e)
                            {
                                if (remoteNode.RemoteEndPoint != null)
                                    DisconnectPeer(remoteNode.RemoteEndPoint, e);
                            }
                        }).Forget();
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e.Message);
                    }
                }
            }
            catch (OperationCanceledException) { }

            this.listenSocket.Dispose();
        }