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;
}