diff --git a/fuzz/travis-fuzz.sh b/fuzz/travis-fuzz.sh index ae85ea9..3af8d1a 100755 --- a/fuzz/travis-fuzz.sh +++ b/fuzz/travis-fuzz.sh @@ -7,7 +7,7 @@ for TARGET in fuzz_targets/*; do if [ -d hfuzz_input/$FILE ]; then HFUZZ_INPUT_ARGS="-f hfuzz_input/$FILE/input" fi - HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz" HFUZZ_RUN_ARGS="-N1000000 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run $FILE + HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz" HFUZZ_RUN_ARGS="-N200000 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run $FILE if [ -f hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT ]; then cat hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index de01451..90e4d2f 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -29,8 +29,6 @@ //! big-endian decimals, etc.) //! -use std::collections::HashMap; -use std::hash::Hash; use std::{mem, u32}; use std::error; @@ -47,6 +45,10 @@ use secp256k1; use util::base58; use util::psbt; +use blockdata::transaction::{TxOut, Transaction, TxIn}; +use network::message_blockdata::Inventory; +use network::address::Address; + /// Encoding error #[derive(Debug)] pub enum Error { @@ -262,6 +264,9 @@ pub trait Encoder { /// Output a boolean fn emit_bool(&mut self, v: bool) -> Result<(), Error>; + + /// Output a byte slice + fn emit_slice(&mut self, v: &[u8]) -> Result<(), Error>; } /// A simple Decoder trait @@ -286,6 +291,9 @@ pub trait Decoder { /// Read a boolean fn read_bool(&mut self) -> Result; + + /// Read a byte slice + fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error>; } macro_rules! encoder_fn { @@ -326,6 +334,10 @@ impl Encoder for W { fn emit_bool(&mut self, v: bool) -> Result<(), Error> { self.write_i8(if v {1} else {0}).map_err(Error::Io) } + #[inline] + fn emit_slice(&mut self, v: &[u8]) -> Result<(), Error> { + self.write_all(v).map_err(Error::Io) + } } impl Decoder for R { @@ -348,6 +360,10 @@ impl Decoder for R { fn read_bool(&mut self) -> Result { Decoder::read_i8(self).map(|bit| bit != 0) } + #[inline] + fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> { + self.read_exact(slice).map_err(Error::Io) + } } /// Maximum size, in bytes, of a vector we are allowed to decode @@ -475,7 +491,9 @@ impl Decodable for bool { impl Encodable for String { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { - self.as_bytes().consensus_encode(s) + let b = self.as_bytes(); + VarInt(b.len() as u64).consensus_encode(s)?; + s.emit_slice(&b) } } @@ -491,21 +509,18 @@ impl Decodable for String { // Arrays macro_rules! impl_array { ( $size:expr ) => ( - impl> Encodable for [T; $size] { + impl Encodable for [u8; $size] { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { - for i in self.iter() { i.consensus_encode(s)?; } - Ok(()) + s.emit_slice(&self[..]) } } - impl + Copy> Decodable for [T; $size] { + impl Decodable for [u8; $size] { #[inline] - fn consensus_decode(d: &mut D) -> Result<[T; $size], self::Error> { - // Set everything to the first decode - let mut ret = [Decodable::consensus_decode(d)?; $size]; - // Set the rest - for item in ret.iter_mut().take($size).skip(1) { *item = Decodable::consensus_decode(d)?; } + fn consensus_decode(d: &mut D) -> Result<[u8; $size], self::Error> { + let mut ret = [0; $size]; + d.read_slice(&mut ret)?; Ok(ret) } } @@ -520,54 +535,105 @@ impl_array!(16); impl_array!(32); impl_array!(33); -impl> Encodable for [T] { +impl Decodable for [u16; 8] { + #[inline] + fn consensus_decode(d: &mut D) -> Result<[u16; 8], self::Error> { + let mut res = [0; 8]; + for i in 0..8 { + res[i] = Decodable::consensus_decode(d)?; + } + Ok(res) + } +} + +impl Encodable for [u16; 8] { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { - VarInt(self.len() as u64).consensus_encode(s)?; for c in self.iter() { c.consensus_encode(s)?; } Ok(()) } } -// Cannot decode a slice - // Vectors -impl> Encodable for Vec { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) } -} - -impl> Decodable for Vec { - #[inline] - fn consensus_decode(d: &mut D) -> Result, self::Error> { - let len = VarInt::consensus_decode(d)?.0; - let byte_size = (len as usize) - .checked_mul(mem::size_of::()) - .ok_or(self::Error::ParseFailed("Invalid length"))?; - if byte_size > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) +macro_rules! impl_vec { + ($type: ty) => { + impl Encodable for Vec<$type> { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + VarInt(self.len() as u64).consensus_encode(s)?; + for c in self.iter() { c.consensus_encode(s)?; } + Ok(()) + } } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } - Ok(ret) + + impl Decodable for Vec<$type> { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let len = VarInt::consensus_decode(d)?.0; + let byte_size = (len as usize) + .checked_mul(mem::size_of::<$type>()) + .ok_or(self::Error::ParseFailed("Invalid length"))?; + if byte_size > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) + } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + Ok(ret) + } + } + } +} +impl_vec!(sha256d::Hash); +impl_vec!(Transaction); +impl_vec!(TxOut); +impl_vec!(TxIn); +impl_vec!(Inventory); +impl_vec!(Vec); +impl_vec!((u32, Address)); +impl_vec!(u64); + +impl Encodable for Vec { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + VarInt(self.len() as u64).consensus_encode(s)?; + s.emit_slice(&self) } } -impl> Encodable for Box<[T]> { +impl Decodable for Vec { #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (&self[..]).consensus_encode(s) } -} - -impl> Decodable for Box<[T]> { - #[inline] - fn consensus_decode(d: &mut D) -> Result, self::Error> { + fn consensus_decode(d: &mut D) -> Result, self::Error> { let len = VarInt::consensus_decode(d)?.0; let len = len as usize; if len > MAX_VEC_SIZE { return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) } let mut ret = Vec::with_capacity(len); - for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + ret.resize(len, 0); + d.read_slice(&mut ret)?; + Ok(ret) + } +} + +impl Encodable for Box<[u8]> { + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { + VarInt(self.len() as u64).consensus_encode(s)?; + s.emit_slice(&self) + } +} + +impl Decodable for Box<[u8]> { + #[inline] + fn consensus_decode(d: &mut D) -> Result, self::Error> { + let len = VarInt::consensus_decode(d)?.0; + let len = len as usize; + if len > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) + } + let mut ret = Vec::with_capacity(len); + ret.resize(len, 0); + d.read_slice(&mut ret)?; Ok(ret.into_boxed_slice()) } } @@ -585,11 +651,7 @@ impl Encodable for CheckedData { fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (self.0.len() as u32).consensus_encode(s)?; sha2_checksum(&self.0).consensus_encode(s)?; - // We can't just pass to the slice encoder since it'll insert a length - for ch in &self.0 { - ch.consensus_encode(s)?; - } - Ok(()) + s.emit_slice(&self.0) } } @@ -599,7 +661,8 @@ impl Decodable for CheckedData { let len: u32 = Decodable::consensus_decode(d)?; let checksum: [u8; 4] = Decodable::consensus_decode(d)?; let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { ret.push(Decodable::consensus_decode(d)?); } + ret.resize(len as usize, 0); + d.read_slice(&mut ret)?; let expected_checksum = sha2_checksum(&ret); if expected_checksum != checksum { Err(self::Error::InvalidChecksum { @@ -640,54 +703,6 @@ tuple_encode!(T0, T1, T2, T3); tuple_encode!(T0, T1, T2, T3, T4, T5); tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); -// References -impl> Encodable for Box { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { (**self).consensus_encode(s) } -} - -impl> Decodable for Box { - #[inline] - fn consensus_decode(d: &mut D) -> Result, self::Error> { - Decodable::consensus_decode(d).map(Box::new) - } -} - -// HashMap -impl Encodable for HashMap - where S: Encoder, - K: Encodable + Eq + Hash, - V: Encodable -{ - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { - VarInt(self.len() as u64).consensus_encode(s)?; - for (key, value) in self.iter() { - key.consensus_encode(s)?; - value.consensus_encode(s)?; - } - Ok(()) - } -} - -impl Decodable for HashMap - where D: Decoder, - K: Decodable + Eq + Hash, - V: Decodable -{ - #[inline] - fn consensus_decode(d: &mut D) -> Result, self::Error> { - let len = VarInt::consensus_decode(d)?.0; - - let mut ret = HashMap::with_capacity(len as usize); - for _ in 0..len { - ret.insert(Decodable::consensus_decode(d)?, - Decodable::consensus_decode(d)?); - } - Ok(ret) - } -} - impl Encodable for sha256d::Hash { fn consensus_encode(&self, s: &mut S) -> Result<(), self::Error> { self.into_inner().consensus_encode(s) @@ -806,7 +821,6 @@ mod tests { #[test] fn serialize_vector_test() { assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]); - assert_eq!(serialize(&[1u8, 2, 3][..]), vec![3u8, 1, 2, 3]); // TODO: test vectors of more interesting objects } @@ -815,13 +829,6 @@ mod tests { assert_eq!(serialize(&"Andrew".to_string()), vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]); } - #[test] - fn serialize_box_test() { - assert_eq!(serialize(&Box::new(1u8)), vec![1u8]); - assert_eq!(serialize(&Box::new(1u16)), vec![1u8, 0]); - assert_eq!(serialize(&Box::new(1u64)), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); - } - #[test] fn deserialize_int_test() { // bool @@ -882,13 +889,5 @@ mod tests { let cd: Result = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5]))); } - - #[test] - fn deserialize_box_test() { - let zero: Result, _> = deserialize(&[0u8]); - let one: Result, _> = deserialize(&[1u8]); - assert_eq!(zero.ok(), Some(Box::new(0))); - assert_eq!(one.ok(), Some(Box::new(1))); - } } diff --git a/src/network/message.rs b/src/network/message.rs index 58d792b..2e01c70 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -99,6 +99,8 @@ pub enum NetworkMessage { Block(block::Block), /// `headers` Headers(Vec), + /// `sendheaders` + SendHeaders, /// `getaddr` GetAddr, // TODO: checkorder, @@ -142,6 +144,7 @@ impl RawNetworkMessage { NetworkMessage::Tx(_) => "tx", NetworkMessage::Block(_) => "block", NetworkMessage::Headers(_) => "headers", + NetworkMessage::SendHeaders => "sendheaders", NetworkMessage::GetAddr => "getaddr", NetworkMessage::Ping(_) => "ping", NetworkMessage::Pong(_) => "pong", @@ -194,6 +197,7 @@ impl Encodable for RawNetworkMessage { NetworkMessage::CFCheckpt(ref dat) => serialize(dat), NetworkMessage::Alert(ref dat) => serialize(dat), NetworkMessage::Verack + | NetworkMessage::SendHeaders | NetworkMessage::MemPool | NetworkMessage::GetAddr => vec![], }).consensus_encode(s) @@ -243,6 +247,7 @@ impl Decodable for RawNetworkMessage { "headers" => NetworkMessage::Headers(>>> ::consensus_decode(&mut mem_d)?.0), + "sendheaders" => NetworkMessage::SendHeaders, "getaddr" => NetworkMessage::GetAddr, "ping" => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?), "pong" => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?), diff --git a/src/util/uint.rs b/src/util/uint.rs index 6a0c9f6..05d4a95 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -348,7 +348,10 @@ macro_rules! construct_uint { impl ::consensus::encode::Decodable for $name { fn consensus_decode(d: &mut D) -> Result<$name, encode::Error> { use consensus::encode::Decodable; - let ret: [u64; $n_words] = Decodable::consensus_decode(d)?; + let mut ret: [u64; $n_words] = [0; $n_words]; + for i in 0..$n_words { + ret[i] = Decodable::consensus_decode(d)?; + } Ok($name(ret)) } }