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; }
public static byte[] EncodeMessage(Message message) { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { EncodeMessage(writer, message); return stream.ToArray(); } }
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()); }
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; }
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; }