public static IBitcoinMessage Parse(BitcoinMessage message)
        {
            Func<BitcoinStreamReader, IBitcoinMessage> readMethod;
            if (!messageReadMethods.TryGetValue(message.Command, out readMethod))
            {
                return null;
            }

            MemoryStream mem = new MemoryStream(message.Payload);
            using (BitcoinStreamReader reader = new BitcoinStreamReader(mem))
            {
                return readMethod(reader);
            }
        }
 private string FormatForLog(BitcoinMessage message)
 {
     StringBuilder sb = new StringBuilder();
     BitcoinMessageFormatter formatter = new BitcoinMessageFormatter("\t");
     sb.AppendFormat("{0} [{1} byte(s)]", message.Command, message.Payload.Length);
     try
     {
         IBitcoinMessage parsedMessage = BitcoinMessageParser.Parse(message);
         if (parsedMessage != null)
         {
             sb.Append("\n");
             sb.Append(formatter.Format(parsedMessage));
         }
     }
     catch (Exception e)
     {
         sb.AppendFormat("\n\tUnable to parse message: {0}", e.Message);
     }
     return sb.ToString();
 }
        /// <summary>
        /// Sends the message to the connected peer.
        /// <para/>
        /// Method is thread-safe.
        /// </summary>
        /// <param name="message">The message to send.</param>
        public void WriteMessage(BitcoinMessage message)
        {
            lock (writeLock)
            {
                byte[] commandBytes = Encoding.ASCII.GetBytes(message.Command);
                if (commandBytes.Length > MaxCommandLength)
                {
                    //todo: handle correctly
                    throw new BitcoinNetworkException($"Command length ({commandBytes.Length}) exeeds maximum command length ({MaxCommandLength}).");
                }

                byte[] header = new byte[MessageHeaderLength];

                Array.Copy(magicBytes, 0, header, 0, 4);
                Array.Copy(commandBytes, 0, header, 4, commandBytes.Length);

                byte[] payloadLengthBytes = BitConverter.GetBytes(message.Payload.Length);
                Array.Copy(payloadLengthBytes, 0, header, 16, 4);

                byte[] checksum = sha256WriterAlg.ComputeHash(sha256WriterAlg.ComputeHash(message.Payload));
                Array.Copy(checksum, 0, header, 20, 4);

                stream.Write(header, 0, header.Length);
                stream.Write(message.Payload, 0, message.Payload.Length);
            }

            if (logger.IsTraceEnabled)
            {
                logger.Trace("Sent message: {0}", FormatForLog(message));
            }
        }
        public BitcoinMessage ReadMessage()
        {
            byte[] header = ReadBytes(MessageHeaderLength);

            int payloadLength = BitConverter.ToInt32(header, 16);

            for (int i = 0; i < 4; i++)
            {
                if (header[i] != magicBytes[i])
                {
                    //todo: handle correctly
                    throw new Exception("The magic value is invalid.");
                }
            }

            if (payloadLength < 0)
            {
                //todo: handle correctly
                throw new Exception(string.Format("Invalid payload length: ({0}).", payloadLength));
            }

            //todo: move to const
            if (payloadLength > MaxPayloadLength)
            {
                //todo: handle correctly
                throw new Exception(string.Format("Payload length is too large: {0}.", payloadLength));
            }

            int commandLength = 12;
            while (commandLength > 0 && header[commandLength + 4 - 1] == 0)
            {
                commandLength--;
            }

            string command = Encoding.ASCII.GetString(header, 4, commandLength);

            byte[] payload = ReadBytes(payloadLength);

            byte[] checksum = sha256ReaderAlg.ComputeHash(sha256ReaderAlg.ComputeHash(payload));

            for (int i = 0; i < 4; i++)
            {
                if (header[20 + i] != checksum[i])
                {
                    //todo: handle correctly
                    throw new Exception("The checksum is invalid.");
                }
            }

            BitcoinMessage message = new BitcoinMessage(command, payload);

            if (logger.IsTraceEnabled)
            {
                logger.Trace("Received message: {0}", FormatForLog(message));
            }

            return message;
        }
        private void HandleMessage(BitcoinMessage message)
        {
            if (message.Command == RejectMessage.Command)
            {
                //todo: stop endpoint / allow messageHandler to process it (be careful of reject message loop)?
                return;
            }

            IBitcoinMessage parsedMessage = BitcoinMessageParser.Parse(message);

            if (parsedMessage is PingMessage)
            {
                PingMessage ping = (PingMessage) parsedMessage;
                WriteMessage(new PongMessage(ping.Nonce));
            }

            if (parsedMessage == null)
            {
                //todo: this is a misuse of the interface
                parsedMessage = message;
            }

            if (messageHandler == null || !messageHandler(this, parsedMessage))
            {
                WriteMessage(new RejectMessage(message.Command, RejectMessage.RejectReason.Malformed, "Unknown command."));
            }
        }
 public void WriteMessage(IBitcoinMessage message)
 {
     BitcoinMessage rawMessage = new BitcoinMessage(message.Command, BitcoinStreamWriter.GetBytes(message.Write));
     conn.WriteMessage(rawMessage);
 }