Exemple #1
0
        public async Task SendMessageAsync(Message message)
        {
            try
            {
                await semaphore.DoAsync(async() =>
                {
                    using (var stream = new NetworkStream(this.socket))
                    {
                        var stopwatch = Stopwatch.StartNew();

                        using (var byteStream = new MemoryStream())
                        {
                            NodeEncoder.EncodeMessage(byteStream, message);

                            var messageBytes = byteStream.ToArray();
                            await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
                        }

                        stopwatch.Stop();

                        if (this.logger.IsTraceEnabled)
                        {
                            this.logger.Trace("Sent {0} in {1} ms\nPayload: {2}".Format2(message.Command, stopwatch.ElapsedMilliseconds, message.Payload.ToHexDataString()));
                        }
                    }
                });
            }
            catch (Exception e)
            {
                Fail(e);
            }
        }
Exemple #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);
        }
Exemple #3
0
        public async Task SendGetData(ImmutableArray <InventoryVector> invVectors)
        {
            await Task.Yield();

            var getDataPayload = Messaging.ConstructInventoryPayload(invVectors);
            var getDataMessage = Messaging.ConstructMessage("getdata", NodeEncoder.EncodeInventoryPayload(getDataPayload));

            await SendMessageAsync(getDataMessage);
        }
Exemple #4
0
        public async Task SendVersion(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, UInt64 nodeId, UInt32 startBlockHeight)
        {
            await Task.Yield();

            var versionPayload = Messaging.ConstructVersionPayload(localEndPoint, remoteEndPoint, nodeId, startBlockHeight);
            var versionMessage = Messaging.ConstructMessage("version", NodeEncoder.EncodeVersionPayload(versionPayload, withRelay: false));

            await SendMessageAsync(versionMessage);
        }
Exemple #5
0
        public async Task SendInventory(ImmutableArray <InventoryVector> invVectors)
        {
            await Task.Yield();

            var invPayload = Messaging.ConstructInventoryPayload(invVectors);
            var invMessage = Messaging.ConstructMessage("inv", NodeEncoder.EncodeInventoryPayload(invPayload));

            await SendMessageAsync(invMessage);
        }
Exemple #6
0
        public async Task SendGetBlocks(ImmutableArray <UInt256> blockLocatorHashes, UInt256 hashStop)
        {
            await Task.Yield();

            var getBlocksPayload = Messaging.ConstructGetBlocksPayload(blockLocatorHashes, hashStop);
            var getBlocksMessage = Messaging.ConstructMessage("getblocks", NodeEncoder.EncodeGetBlocksPayload(getBlocksPayload));

            await SendMessageAsync(getBlocksMessage);
        }
Exemple #7
0
        public void TestWireEncodeNetworkAddress()
        {
            var actual = NodeEncoder.EncodeNetworkAddress(NETWORK_ADDRESS_1);

            CollectionAssert.AreEqual(NETWORK_ADDRESS_1_BYTES.ToList(), actual.ToList());
        }
 private static NetworkAddressKey DecodeKey(byte[] networkAddressKeyBytes)
 {
     return(NodeEncoder.DecodeNetworkAddressKey(networkAddressKeyBytes));
 }
 private static byte[] EncodeKey(NetworkAddressKey networkAddressKey)
 {
     return(NodeEncoder.EncodeNetworkAddressKey(networkAddressKey));
 }
Exemple #10
0
        public void TestWireDecodeGetBlocksPayload()
        {
            var actual = NodeEncoder.EncodeGetBlocksPayload(NodeEncoder.DecodeGetBlocksPayload(GET_BLOCKS_PAYLOAD_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(GET_BLOCKS_PAYLOAD_1_BYTES.ToList(), actual.ToList());
        }
Exemple #11
0
        public void TestWireDecodeAlertPayload()
        {
            var actual = NodeEncoder.EncodeAlertPayload(NodeEncoder.DecodeAlertPayload(ALERT_PAYLOAD_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(ALERT_PAYLOAD_1_BYTES.ToList(), actual.ToList());
        }
Exemple #12
0
        public void TestWireDecodeVersionPayloadWithRelay()
        {
            var actual = NodeEncoder.EncodeVersionPayload(NodeEncoder.DecodeVersionPayload(VERSION_PAYLOAD_2_RELAY_BYTES.ToArray(), VERSION_PAYLOAD_2_RELAY_BYTES.Length), withRelay: true);

            CollectionAssert.AreEqual(VERSION_PAYLOAD_2_RELAY_BYTES.ToList(), actual.ToList());
        }
Exemple #13
0
        public void TestWireEncodeAddressPayload()
        {
            var actual = NodeEncoder.EncodeAddressPayload(ADDRESS_PAYLOAD_1);

            CollectionAssert.AreEqual(ADDRESS_PAYLOAD_1_BYTES.ToList(), actual.ToList());
        }
Exemple #14
0
        public void TestWireEncodeVersionPayloadWithoutRelay()
        {
            var actual = NodeEncoder.EncodeVersionPayload(VERSION_PAYLOAD_1_NO_RELAY, withRelay: false);

            CollectionAssert.AreEqual(VERSION_PAYLOAD_1_NO_RELAY_BYTES.ToList(), actual.ToList());
        }
Exemple #15
0
        public void TestWireDecodeNetworkAddressWithTime()
        {
            var actual = NodeEncoder.EncodeNetworkAddressWithTime(NodeEncoder.DecodeNetworkAddressWithTime(NETWORK_ADDRESS_WITH_TIME_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(NETWORK_ADDRESS_WITH_TIME_1_BYTES.ToList(), actual.ToList());
        }
Exemple #16
0
        public void TestWireDecodeInventoryPayload()
        {
            var actual = NodeEncoder.EncodeInventoryPayload(NodeEncoder.DecodeInventoryPayload(INVENTORY_PAYLOAD_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(INVENTORY_PAYLOAD_1_BYTES.ToList(), actual.ToList());
        }
Exemple #17
0
        public void TestWireDecodeInventoryVector()
        {
            var actual = NodeEncoder.EncodeInventoryVector(NodeEncoder.DecodeInventoryVector(INVENTORY_VECTOR_1_BYTES.ToArray()));

            CollectionAssert.AreEqual(INVENTORY_VECTOR_1_BYTES.ToList(), actual.ToList());
        }
 private static byte[] EncodeValue(NetworkAddressWithTime networkAddressWithTime)
 {
     return(NodeEncoder.EncodeNetworkAddressWithTime(networkAddressWithTime));
 }
Exemple #19
0
        public void TestWireEncodeMessage()
        {
            var actual = NodeEncoder.EncodeMessage(MESSAGE_1);

            CollectionAssert.AreEqual(MESSAGE_1_BYTES.ToList(), actual.ToList());
        }
 private static NetworkAddressWithTime DecodeValue(byte[] networkAddressWithTimeBytes)
 {
     return(NodeEncoder.DecodeNetworkAddressWithTime(networkAddressWithTimeBytes));
 }
Exemple #21
0
        private Message WireDecodeMessage(UInt32 magic, Stream stream)
        {
            byte[]  payload;
            Message message;

            using (var reader = new BinaryReader(stream, Encoding.ASCII, leaveOpen: true))
            {
                var command         = reader.ReadFixedString(12);
                var payloadSize     = reader.ReadUInt32();
                var payloadChecksum = reader.ReadUInt32();

                payload = reader.ReadBytes(payloadSize.ToIntChecked());

                if (!Messaging.VerifyPayloadChecksum(payloadChecksum, payload))
                {
                    throw new Exception(string.Format("Checksum failed for {0}", command));
                }

                message = new Message
                          (
                    Magic: magic,
                    Command: command,
                    PayloadSize: payloadSize,
                    PayloadChecksum: payloadChecksum,
                    Payload: payload.ToImmutableArray()
                          );
            }

            switch (message.Command)
            {
            case "addr":
            {
                var addressPayload = NodeEncoder.DecodeAddressPayload(payload);

                var handler = this.OnReceivedAddresses;
                if (handler != null)
                {
                    handler(addressPayload.NetworkAddresses);
                }
            }
            break;

            case "alert":
            {
                var alertPayload = NodeEncoder.DecodeAlertPayload(payload);
            }
            break;

            case "block":
            {
                var block = DataEncoder.DecodeBlock(payload);

                var handler = this.OnBlock;
                if (handler != null)
                {
                    handler(this.owner, block);
                }
            }
            break;

            case "getblocks":
            {
                var getBlocksPayload = NodeEncoder.DecodeGetBlocksPayload(payload);

                var handler = this.OnGetBlocks;
                if (handler != null)
                {
                    handler(getBlocksPayload);
                }
            }
            break;

            case "getheaders":
            {
                var getHeadersPayload = NodeEncoder.DecodeGetBlocksPayload(payload);

                var handler = this.OnGetHeaders;
                if (handler != null)
                {
                    handler(getHeadersPayload);
                }
            }
            break;

            case "getdata":
            {
                var invPayload = NodeEncoder.DecodeInventoryPayload(payload);

                var handler = this.OnGetData;
                if (handler != null)
                {
                    handler(invPayload);
                }
            }
            break;

            case "headers":
            {
                var blockHeaders = ImmutableList.CreateBuilder <BlockHeader>();

                using (var headerStream = new MemoryStream(payload))
                    using (var reader = new BinaryReader(headerStream))
                    {
                        var headerCount = reader.ReadVarInt().ToIntChecked();

                        for (var i = 0; i < headerCount; i++)
                        {
                            var blockHeader = DataEncoder.DecodeBlockHeader(headerStream);
                            //TODO wiki says this is a byte and a var int, which is it?
                            var txCount = reader.ReadVarInt();

                            blockHeaders.Add(blockHeader);
                        }
                    }

                var handler = this.OnBlockHeaders;
                if (handler != null)
                {
                    handler(this.owner, blockHeaders.ToImmutable());
                }
            }
            break;

            case "inv":
            {
                var invPayload = NodeEncoder.DecodeInventoryPayload(payload);

                var handler = this.OnInventoryVectors;
                if (handler != null)
                {
                    handler(invPayload.InventoryVectors);
                }
            }
            break;

            case "notfound":
            {
                var invPayload = NodeEncoder.DecodeInventoryPayload(payload);

                var handler = this.OnNotFound;
                if (handler != null)
                {
                    handler(invPayload.InventoryVectors);
                }
            }
            break;

            case "ping":
            {
                var handler = this.OnPing;
                if (handler != null)
                {
                    handler(payload.ToImmutableArray());
                }
            }
            break;

            case "tx":
            {
                var tx = DataEncoder.DecodeTransaction(payload);

                var handler = this.OnTransaction;
                if (handler != null)
                {
                    handler(tx);
                }
            }
            break;

            case "version":
            {
                var versionPayload = NodeEncoder.DecodeVersionPayload(payload, payload.Length);

                var handler = this.OnVersion;
                if (handler != null)
                {
                    handler(versionPayload);
                }
            }
            break;

            case "verack":
            {
                var handler = this.OnVersionAcknowledged;
                if (handler != null)
                {
                    handler();
                }
            }
            break;

            default:
            {
                this.logger.Warn("Unhandled incoming message: {0}".Format2(message.Command));
            }
            break;
            }

            //TODO
            //if (payloadStream.Position != payloadStream.Length)
            //{
            //    var exMessage = string.Format("Wrong number of bytes read for {0}, parser error: read {1} bytes from a {2} byte payload", message.Command, payloadStream.Position, payloadStream.Length);
            //    Debug.WriteLine(exMessage);
            //    throw new Exception(exMessage);
            //}

            return(message);
        }