Beispiel #1
0
        public static Message ConstructMessage(string command, byte[] payload)
        {
            var message = new Message
            (
                Magic: Messaging.Magic,
                Command: command,
                PayloadSize: (UInt32)payload.Length,
                PayloadChecksum: CalculatePayloadChecksum(payload),
                Payload: payload.ToImmutableArray()
            );

            return message;
        }
Beispiel #2
0
 public static byte[] EncodeMessage(Message message)
 {
     using (var stream = new MemoryStream())
     using (var writer = new BinaryWriter(stream))
     {
         EncodeMessage(writer, message);
         return stream.ToArray();
     }
 }
Beispiel #3
0
 public static void EncodeMessage(BinaryWriter writer, Message message)
 {
     writer.WriteUInt32(message.Magic);
     writer.WriteFixedString(12, message.Command);
     writer.WriteUInt32(message.PayloadSize);
     writer.WriteUInt32(message.PayloadChecksum);
     writer.WriteBytes(message.PayloadSize.ToIntChecked(), message.Payload.ToArray());
 }
Beispiel #4
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 = NodeEncoder.DecodeAddressPayload(payload);

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

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

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

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

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

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

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

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

                case "getdata":
                    {
                        var invPayload = NodeEncoder.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 = NodeEncoder.DecodeInventoryPayload(payload);

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

                case "notfound":
                    {
                        var invPayload = NodeEncoder.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 = NodeEncoder.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;
        }
Beispiel #5
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))
                        {
                            NodeEncoder.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);
            }
        }
        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($"Checksum failed for {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);

                        this.OnReceivedAddresses?.Invoke(addressPayload.NetworkAddresses);
                    }
                    break;

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

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

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

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

                        this.OnGetBlocks?.Invoke(getBlocksPayload);
                    }
                    break;

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

                        this.OnGetHeaders?.Invoke(getHeadersPayload);
                    }
                    break;

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

                        this.OnGetData?.Invoke(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(reader);
                                //TODO wiki says this is a byte and a var int, which is it?
                                var txCount = reader.ReadVarInt();

                                blockHeaders.Add(blockHeader);
                            }
                        }

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

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

                        this.OnInventoryVectors?.Invoke(invPayload.InventoryVectors);
                    }
                    break;

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

                        this.OnNotFound?.Invoke(invPayload.InventoryVectors);
                    }
                    break;

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

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

                        this.OnTransaction?.Invoke(tx);
                    }
                    break;

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

                        this.OnVersion?.Invoke(versionPayload);
                    }
                    break;

                case "verack":
                    {
                        this.OnVersionAcknowledged?.Invoke();
                    }
                    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;
        }