示例#1
0
        public async void New_AfterConnecting_FiresMessageReceivedWhenDataAvailable()
        {
            var versionMessage = new MsgVersion()
            {
                ProtocolVersion = 1
            };
            var versionMessageHeader = new MessageHeader(_currencyNet, MsgCommand.Version, versionMessage.Encode());

            // Write the header + message to the READ stream, then reset the stream position.
            var writer = new BinaryWriter(_readStream);

            versionMessageHeader.Encode(writer);
            versionMessage.Encode(writer);
            _readStream.Position = 0;

            var subject = new Peer(_networkClientMock.Object, _currencyNet);
            await subject.ConnectAsync();

            // Closure to capture the data passed to the raised event
            PeerMessageReceivedArgs eventArgs = null;
            var resetEvent = new ManualResetEvent(false);

            subject.MessageReceived += (sender, e) =>
            {
                eventArgs = e;
                resetEvent.Set();
            };

            resetEvent.WaitOne(TimeSpan.FromSeconds(1));

            Assert.True(eventArgs != null);
            Assert.Equal(versionMessageHeader.Checksum, (IEnumerable <byte>)eventArgs.Header.Checksum);
        }
示例#2
0
        private async Task ConnectAndHandshake(Peer peer, bool isIncoming)
        {
            // connect
            await peer.ConnectAsync();

            if (!peer.IsConnected)
            {
                throw new Exception();
            }

            // 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: DateTime.UtcNow.ToUnixTime(),
                NetworkAddress: new NetworkAddress
                (
                    Services: versionPayload.LocalAddress.Services,
                    IPv6Address: versionPayload.LocalAddress.IPv6Address,
                    Port: versionPayload.LocalAddress.Port
                )
                                        );

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

            if (isIncoming)
            {
                Interlocked.Increment(ref this.incomingCount);
            }

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

            peer.OnDisconnect += DisconnectPeer;
            RaisePeerConnected(peer);
        }
示例#3
0
        public async void ConnectAsync_WithMockNetworkClient_ConnectsAndSendsVersionMessage()
        {
            var versionMessage = new MsgVersion()
            {
                ProtocolVersion = 1
            };
            var versionMessageHeader = new MessageHeader(_currencyNet, MsgCommand.Version, versionMessage.Encode());
            var expected             = versionMessageHeader.Encode().Concat(versionMessage.Encode()).ToArray();

            var subject = new Peer(_networkClientMock.Object, _currencyNet);
            await subject.ConnectAsync();

            _networkClientMock.Verify(m => m.ConnectAsync(), Times.Once);

            // The data written to the stream should be the entire version message
            var actualBytesWritten = _writeStream.ToArray();

            Assert.Equal(expected.Length, actualBytesWritten.Length);
            Assert.Equal(actualBytesWritten, (IEnumerable <byte>)expected);
        }
示例#4
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 = NetworkEncoder.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();
        }