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

                        var byteStream = new MemoryStream();
                        NetworkEncoder.EncodeMessage(byteStream, message);

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

                        stopwatch.Stop();
                        //Debug.WriteLine("-------------------------");
                        //Debug.WriteLine(string.Format("Sent {0} in {1} ms\nPayload: {2}", message.Command, stopwatch.ElapsedMilliseconds, message.Payload.ToHexDataString()));
                    }
                });
            }
            catch (Exception e)
            {
                Fail(e);
            }
        }
예제 #2
0
        public async Task SendMessageAsync(Message message)
        {
            try
            {
                await semaphore.DoAsync(async() =>
                {
                    using (var stream = new NetworkStream(socket))
                    {
                        var stopwatch = Stopwatch.StartNew();

                        using (var byteStream = new MemoryStream())
                            using (var writer = new BinaryWriter(byteStream))
                            {
                                NetworkEncoder.EncodeMessage(writer, message);

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

                        stopwatch.Stop();

                        if (logger.IsTraceEnabled)
                        {
                            logger.Trace($"Sent {message.Command} in {stopwatch.ElapsedMilliseconds} ms\nPayload: {message.Payload.ToArray().ToHexDataString()}");
                        }
                    }
                });
            }
            catch (Exception e)
            {
                Fail(e);
            }
        }
예제 #3
0
        public async Task SendVersion(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, UInt64 nodeId, UInt32 startBlockHeight)
        {
            var versionPayload = Messaging.ConstructVersionPayload(localEndPoint, remoteEndPoint, nodeId, startBlockHeight);
            var versionMessage = Messaging.ConstructMessage("version", NetworkEncoder.EncodeVersionPayload(versionPayload, withRelay: false));

            await SendMessageAsync(versionMessage);
        }
예제 #4
0
        public async Task SendGetBlocks(ImmutableArray <UInt256> blockLocatorHashes, UInt256 hashStop)
        {
            var getBlocksPayload = Messaging.ConstructGetBlocksPayload(blockLocatorHashes, hashStop);
            var getBlocksMessage = Messaging.ConstructMessage("getblocks", NetworkEncoder.EncodeGetBlocksPayload(getBlocksPayload));

            await SendMessageAsync(getBlocksMessage);
        }
예제 #5
0
        public async Task SendGetData(ImmutableArray <InventoryVector> invVectors)
        {
            await Task.Yield();

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

            await SendMessageAsync(getDataMessage);
        }
예제 #6
0
        public async Task SendInventory(ImmutableArray <InventoryVector> invVectors)
        {
            await Task.Yield();

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

            await SendMessageAsync(invMessage);
        }
예제 #7
0
        private async Task <Message> WireDecodeMessage(UInt32 magic)
        {
            var command         = DataDecoder.DecodeFixedString(await ReceiveExactly(12));
            var payloadSize     = DataDecoder.DecodeUInt32(await ReceiveExactly(4));
            var payloadChecksum = DataDecoder.DecodeUInt32(await ReceiveExactly(4));
            var payload         = await ReceiveExactly(payloadSize.ToIntChecked());

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

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

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

                OnReceivedAddresses?.Invoke(owner, addressPayload.NetworkAddresses);
            }
            break;

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

            case "block":
            {
                var block = DataDecoder.DecodeBlock(null, payload);

                OnBlock?.Invoke(owner, block);
            }
            break;

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

                OnGetBlocks?.Invoke(owner, getBlocksPayload);
            }
            break;

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

                OnGetHeaders?.Invoke(owner, getHeadersPayload);
            }
            break;

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

                OnGetData?.Invoke(owner, invPayload);
            }
            break;

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

                var offset      = 0;
                var headerCount = payload.ReadVarInt(ref offset).ToIntChecked();

                for (var i = 0; i < headerCount; i++)
                {
                    var blockHeader = DataDecoder.DecodeBlockHeader(null, payload, ref offset);
                    // ignore tx count var int
                    payload.ReadVarInt(ref offset);

                    blockHeaders.Add(blockHeader);
                }

                OnBlockHeaders?.Invoke(owner, blockHeaders.ToImmutable());
            }
            break;

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

                OnInventoryVectors?.Invoke(owner, invPayload.InventoryVectors);
            }
            break;

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

                OnNotFound?.Invoke(owner, invPayload.InventoryVectors);
            }
            break;

            case "ping":
            {
                OnPing?.Invoke(owner, payload.ToImmutableArray());
            }
            break;

            case "tx":
            {
                var tx = DataDecoder.DecodeEncodedTx(null, payload);

                OnTransaction?.Invoke(owner, tx);
            }
            break;

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

                OnVersion?.Invoke(owner, versionPayload);
            }
            break;

            case "verack":
            {
                OnVersionAcknowledged?.Invoke(owner);
            }
            break;

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

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

            return(message);
        }
예제 #8
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.Read4Bytes();
                var payloadChecksum = reader.Read4Bytes();

                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 = NetworkEncoder.DecodeAddressPayload(payload.ToMemoryStream());

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

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

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

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

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

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

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

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

            case "headers":
            {
                var headerStream = payload.ToMemoryStream();
                using (var reader = new BinaryReader(headerStream))
                {
                    var headerCount = reader.ReadVarInt().ToIntChecked();

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

                        var handler = this.OnBlockHeader;
                        if (handler != null)
                        {
                            handler(blockHeader);
                        }
                    }
                }
            }
            break;

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

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

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

                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 = NetworkEncoder.DecodeTransaction(payload.ToMemoryStream());

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

            case "version":
            {
                var versionPayload = NetworkEncoder.DecodeVersionPayload(payload.ToMemoryStream(), payload.Length);
                //Debug.WriteLine(string.Format("{0}, {1}", versionPayload.RemoteAddress.ToIPEndPoint(), this.socket.RemoteEndPoint));

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

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

            default:
            {
                Debug.WriteLine("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);
        }