diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index 163eeda1..20ca31ec 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -80,12 +80,6 @@ pub enum Error { ParseFailed(&'static str), /// Unsupported Segwit flag UnsupportedSegwitFlag(u8), - /// Unrecognized network command with its length - UnrecognizedNetworkCommand(String, usize), - /// Invalid Inventory type - UnknownInventoryType(u32), - /// The network command is longer than the maximum allowed (12 chars) - NetworkCommandTooLong(String), } impl fmt::Display for Error { @@ -104,10 +98,6 @@ impl fmt::Display for Error { Error::ParseFailed(ref e) => write!(f, "parse failed: {}", e), Error::UnsupportedSegwitFlag(ref swflag) => write!(f, "unsupported segwit version: {}", swflag), - Error::UnrecognizedNetworkCommand(ref nwcmd, _) => write!(f, - "unrecognized network command: {}", nwcmd), - Error::UnknownInventoryType(ref tp) => write!(f, "Unknown Inventory type: {}", tp), - Error::NetworkCommandTooLong(ref cmd) => write!(f, "Network Command too long: {}", cmd), } } } @@ -123,10 +113,7 @@ impl error::Error for Error { | Error::NonMinimalVarInt | Error::UnknownNetworkMagic(..) | Error::ParseFailed(..) - | Error::UnsupportedSegwitFlag(..) - | Error::UnrecognizedNetworkCommand(..) - | Error::UnknownInventoryType(..) - | Error::NetworkCommandTooLong(..) => None, + | Error::UnsupportedSegwitFlag(..) => None, } } } diff --git a/src/network/message.rs b/src/network/message.rs index ca954685..43df567c 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -109,9 +109,9 @@ pub struct RawNetworkMessage { pub payload: NetworkMessage } -#[derive(Clone, PartialEq, Eq, Debug)] /// A Network message payload. Proper documentation is available on at /// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification) +#[derive(Clone, PartialEq, Eq, Debug)] pub enum NetworkMessage { /// `version` Version(message_network::VersionMessage), @@ -173,10 +173,22 @@ pub enum NetworkMessage { AddrV2(Vec), /// `sendaddrv2` SendAddrV2, + + /// Any other message. + Unknown { + /// The command of this message. + command: CommandString, + /// The payload of this message. + payload: Vec, + } } impl NetworkMessage { - /// Return the message command. This is useful for debug outputs. + /// Return the message command as a static string reference. + /// + /// This returns `"unknown"` for [NetworkMessage::Unknown], + /// regardless of the actual command in the unknown message. + /// Use the [command] method to get the command for unknown messages. pub fn cmd(&self) -> &'static str { match *self { NetworkMessage::Version(_) => "version", @@ -207,17 +219,25 @@ impl NetworkMessage { NetworkMessage::WtxidRelay => "wtxidrelay", NetworkMessage::AddrV2(_) => "addrv2", NetworkMessage::SendAddrV2 => "sendaddrv2", + NetworkMessage::Unknown { .. } => "unknown", } } /// Return the CommandString for the message command. pub fn command(&self) -> CommandString { - CommandString::try_from(self.cmd()).expect("cmd returns valid commands") + match *self { + NetworkMessage::Unknown { command: ref c, .. } => c.clone(), + _ => CommandString::try_from(self.cmd()).expect("cmd returns valid commands") + } } } impl RawNetworkMessage { - /// Return the message command. This is useful for debug outputs. + /// Return the message command as a static string reference. + /// + /// This returns `"unknown"` for [NetworkMessage::Unknown], + /// regardless of the actual command in the unknown message. + /// Use the [command] method to get the command for unknown messages. pub fn cmd(&self) -> &'static str { self.payload.cmd() } @@ -281,8 +301,9 @@ impl Encodable for RawNetworkMessage { | NetworkMessage::SendHeaders | NetworkMessage::MemPool | NetworkMessage::GetAddr - | NetworkMessage::WtxidRelay => vec![], + | NetworkMessage::WtxidRelay | NetworkMessage::SendAddrV2 => vec![], + NetworkMessage::Unknown { payload: ref data, .. } => serialize(data), }).consensus_encode(&mut s)?; Ok(len) } @@ -314,12 +335,11 @@ impl Decodable for HeaderDeserializationWrapper { impl Decodable for RawNetworkMessage { fn consensus_decode(mut d: D) -> Result { let magic = Decodable::consensus_decode(&mut d)?; - let cmd = CommandString::consensus_decode(&mut d)?.0; + let cmd = CommandString::consensus_decode(&mut d)?; let raw_payload = CheckedData::consensus_decode(&mut d)?.0; - let raw_payload_len = raw_payload.len(); let mut mem_d = Cursor::new(raw_payload); - let payload = match &cmd[..] { + let payload = match &cmd.0[..] { "version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?), "verack" => NetworkMessage::Verack, "addr" => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?), @@ -350,7 +370,10 @@ impl Decodable for RawNetworkMessage { "wtxidrelay" => NetworkMessage::WtxidRelay, "addrv2" => NetworkMessage::AddrV2(Decodable::consensus_decode(&mut mem_d)?), "sendaddrv2" => NetworkMessage::SendAddrV2, - _ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd.into_owned(), 4 + 12 + 4 + 4 + raw_payload_len)), // magic + msg str + payload len + checksum + payload + _ => NetworkMessage::Unknown { + command: cmd, + payload: mem_d.into_inner(), + } }; Ok(RawNetworkMessage { magic: magic, diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs index 3f4c1954..ef82552d 100644 --- a/src/network/message_blockdata.rs +++ b/src/network/message_blockdata.rs @@ -41,6 +41,13 @@ pub enum Inventory { WitnessTransaction(Txid), /// Witness Block WitnessBlock(BlockHash), + /// Unknown inventory type + Unknown { + /// The inventory item type. + inv_type: u32, + /// The hash of the inventory item + hash: [u8; 32], + } } impl Encodable for Inventory { @@ -62,6 +69,7 @@ impl Encodable for Inventory { Inventory::WTx(w) => encode_inv!(5, w), Inventory::WitnessTransaction(ref t) => encode_inv!(0x40000001, t), Inventory::WitnessBlock(ref b) => encode_inv!(0x40000002, b), + Inventory::Unknown { inv_type: t, hash: ref d } => encode_inv!(t, d), }) } } @@ -77,7 +85,10 @@ impl Decodable for Inventory { 5 => Inventory::WTx(Decodable::consensus_decode(&mut d)?), 0x40000001 => Inventory::WitnessTransaction(Decodable::consensus_decode(&mut d)?), 0x40000002 => Inventory::WitnessBlock(Decodable::consensus_decode(&mut d)?), - tp => return Err(encode::Error::UnknownInventoryType(tp)), + tp => Inventory::Unknown { + inv_type: tp, + hash: Decodable::consensus_decode(&mut d)?, + } }) } } diff --git a/src/network/message_network.rs b/src/network/message_network.rs index c3d90940..5f033004 100644 --- a/src/network/message_network.rs +++ b/src/network/message_network.rs @@ -84,8 +84,8 @@ impl_consensus_encoding!(VersionMessage, version, services, timestamp, receiver, sender, nonce, user_agent, start_height, relay); -#[derive(PartialEq, Eq, Clone, Copy, Debug)] /// message rejection reason as a code +#[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum RejectReason { /// malformed message Malformed = 0x01, diff --git a/src/network/stream_reader.rs b/src/network/stream_reader.rs index 3ab347ec..501bf607 100644 --- a/src/network/stream_reader.rs +++ b/src/network/stream_reader.rs @@ -68,10 +68,6 @@ impl StreamReader { return Err(encode::Error::Io(io::Error::from(io::ErrorKind::UnexpectedEof))); } }, - Err(encode::Error::UnrecognizedNetworkCommand(message, len)) => { - self.unparsed.drain(..len); - return Err(encode::Error::UnrecognizedNetworkCommand(message, len)) - }, Err(err) => return Err(err), // We have successfully read from the buffer Ok((message, index)) => {