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); }
private async Task ReadStream() { while (!Closing) { try { //try to read a header var hdata = new byte[24]; await Stream.ReadAsyncExact(hdata, 0, hdata.Length); var h = new MessageHeader(); h.ReadFromPayload(hdata, 0); if (h != null) { //read the payload var pl = new byte[h.PayloadSize]; await Stream.ReadAsyncExact(pl, 0, pl.Length); bool checksumOk = false; //verify hash using (var sha = SHA256.Create()) { var h1 = sha.ComputeHash(pl); var h2 = sha.ComputeHash(h1); checksumOk = h2[0] == h.Checksum[0] && h2[1] == h.Checksum[1] && h2[2] == h.Checksum[2] && h2[3] == h.Checksum[3]; } if (checksumOk) { switch (h.Command) { case "addr\0\0\0\0\0\0\0\0": { if (OnAddr != null) { var a = new Addr(); a.ReadFromPayload(pl, 0); await OnAddr?.Invoke(this, a); } break; } case "alert\0\0\0\0\0\0\0": { if (OnAlert != null) { var a = new Alert(); a.ReadFromPayload(pl, 0); await OnAlert?.Invoke(this, a); } break; } case "feefilter\0\0\0": { if (OnFeeFilter != null) { var f = new FeeFilter(); f.ReadFromPayload(pl, 0); await OnFeeFilter?.Invoke(this, f); } break; } case "filteradd\0\0\0": { if (OnFilterAdd != null) { var f = new FilterAdd(); f.ReadFromPayload(pl, 0); await OnFilterAdd?.Invoke(this, f); } break; } case "filterclear\0": { if (OnFilterClear != null) { var f = new FilterClear(); f.ReadFromPayload(pl, 0); await OnFilterClear?.Invoke(this, f); } break; } case "filterload\0\0": { if (OnFilterLoad != null) { var f = new FilterLoad(); f.ReadFromPayload(pl, 0); await OnFilterLoad?.Invoke(this, f); } break; } case "getaddr\0\0\0\0\0": { if (OnGetAddr != null) { var ga = new GetAddr(); ga.ReadFromPayload(pl, 0); await OnGetAddr?.Invoke(this, ga); } break; } case "getblocks\0\0\0": { if (OnGetBlocks != null) { var gb = new GetBlocks(); gb.ReadFromPayload(pl, 0); await OnGetBlocks?.Invoke(this, gb); } break; } case "getdata\0\0\0\0\0": { if (OnGetData != null) { var gd = new GetData(); gd.ReadFromPayload(pl, 0); await OnGetData?.Invoke(this, gd); } break; } case "getheaders\0\0": { if (OnGetHeaders != null) { var gh = new GetHeaders(); gh.ReadFromPayload(pl, 0); await OnGetHeaders?.Invoke(this, gh); } break; } case "headers\0\0\0\0\0": { if (OnHeaders != null) { var hd = new Headers(); hd.ReadFromPayload(pl, 0); await OnHeaders?.Invoke(this, hd); } break; } case "inv\0\0\0\0\0\0\0\0\0": { if (OnInv != null) { var iv = new Inv(); iv.ReadFromPayload(pl, 0); await OnInv?.Invoke(this, iv); } break; } case "mempool\0\0\0\0\0": { if (OnMemPool != null) { var mp = new MemPool(); mp.ReadFromPayload(pl, 0); await OnMemPool?.Invoke(this, mp); } break; } case "notfound\0\0\0\0": { if (OnNotFound != null) { var nf = new NotFound(); nf.ReadFromPayload(pl, 0); await OnNotFound?.Invoke(this, nf); } break; } case "ping\0\0\0\0\0\0\0\0": { if (OnPing != null) { var ping = new Ping(); ping.ReadFromPayload(pl, 0); await OnPing?.Invoke(this, ping); } break; } case "pong\0\0\0\0\0\0\0\0": { if (OnPong != null) { var pong = new Pong(); pong.ReadFromPayload(pl, 0); await OnPong?.Invoke(this, pong); } break; } case "reject\0\0\0\0\0\0": { if (OnReject != null) { var re = new Reject(); re.ReadFromPayload(pl, 0); await OnReject?.Invoke(this, re); } break; } case "sendheaders\0": { if (OnSendHeaders != null) { var sh = new SendHeaders(); sh.ReadFromPayload(pl, 0); await OnSendHeaders?.Invoke(this, sh); } break; } case "verack\0\0\0\0\0\0": { if (OnVerAck != null) { var va = new VerAck(); va.ReadFromPayload(pl, 0); await OnVerAck.Invoke(this, va); } break; } case "version\0\0\0\0\0": { if (OnVersion != null) { var v = new bitcoin_lib.P2P.Version(""); v.ReadFromPayload(pl, 0); await OnVersion?.Invoke(this, v); } break; } default: { //Console.WriteLine($"Got cmd: {h.Command}"); break; } } } else { Closing = true; } } } catch (Exception ex) { Closing = true; } } }