public static Message Parse( NetMQMessage raw, bool reply, AppProtocolVersion localVersion, IImmutableSet <PublicKey> trustedAppProtocolVersionSigners, DifferentAppProtocolVersionEncountered differentAppProtocolVersionEncountered) { if (raw.FrameCount == 0) { throw new ArgumentException("Can't parse empty NetMQMessage."); } // (reply == true) [version, type, peer, sign, frames...] // (reply == false) [identity, version, type, peer, sign, frames...] NetMQFrame[] remains = reply ? raw.ToArray() : raw.Skip(1).ToArray(); var versionToken = remains[(int)MessageFrame.Version].ConvertToString(); AppProtocolVersion remoteVersion = AppProtocolVersion.FromToken(versionToken); Peer remotePeer = null; try { remotePeer = DeserializePeer(remains[(int)MessageFrame.Peer].ToByteArray()); } catch (Exception) { // If failed to find out remotePeer, leave it null. } if (!IsAppProtocolVersionValid( remotePeer, localVersion, remoteVersion, trustedAppProtocolVersionSigners, differentAppProtocolVersionEncountered)) { throw new DifferentAppProtocolVersionException( "Received message's version is not valid.", reply ? null : raw[0].Buffer.ToArray(), localVersion, remoteVersion); } var rawType = (MessageType)remains[(int)MessageFrame.Type].ConvertToInt32(); var peer = remains[(int)MessageFrame.Peer].ToByteArray(); byte[] signature = remains[(int)MessageFrame.Sign].ToByteArray(); NetMQFrame[] body = remains.Skip(CommonFrames).ToArray(); // FIXME: The below code is too repetitive and prone to miss to add, which means, // when you add a new message type, you adds an enum member to MessageType and // a corresponding subclass of Message, but misses to add that correspondence here, // you may take a long time to be aware you've missed here, because the code is still // built well and it looks like just Swarm<T> silently ignore new messages. // At least this correspondence map should not be here. var types = new Dictionary <MessageType, Type> { { MessageType.Ping, typeof(Ping) }, { MessageType.Pong, typeof(Pong) }, { MessageType.GetBlockHashes, typeof(GetBlockHashes) }, { MessageType.BlockHashes, typeof(BlockHashes) }, { MessageType.TxIds, typeof(TxIds) }, { MessageType.GetBlocks, typeof(GetBlocks) }, { MessageType.GetTxs, typeof(GetTxs) }, { MessageType.Blocks, typeof(Blocks) }, { MessageType.Tx, typeof(Tx) }, { MessageType.FindNeighbors, typeof(FindNeighbors) }, { MessageType.Neighbors, typeof(Neighbors) }, { MessageType.GetRecentStates, typeof(GetRecentStates) }, { MessageType.RecentStates, typeof(RecentStates) }, { MessageType.BlockHeaderMessage, typeof(BlockHeaderMessage) }, { MessageType.GetChainStatus, typeof(GetChainStatus) }, { MessageType.ChainStatus, typeof(ChainStatus) }, { MessageType.GetBlockStates, typeof(GetBlockStates) }, { MessageType.BlockStates, typeof(BlockStates) }, { MessageType.DifferentVersion, typeof(DifferentVersion) }, }; if (!types.TryGetValue(rawType, out Type type)) { throw new InvalidMessageException( $"Can't determine NetMQMessage. [type: {rawType}]"); } var message = (Message)Activator.CreateInstance( type, new[] { body }); message.Version = remoteVersion; message.Remote = remotePeer; if (!message.Remote.PublicKey.Verify(body.ToByteArray(), signature)) { throw new InvalidMessageException( "The message signature is invalid" ); } if (!reply) { message.Identity = raw[0].Buffer.ToArray(); } return(message); }