From cc1fc5c0cc07d2f0ac15a3fbcc76005545caafc1 Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Mon, 17 Sep 2018 16:54:51 +1000 Subject: [PATCH 01/12] Update ssz implementation of int types --- ssz/src/encode.rs | 7 +++ ssz/src/impl_encode.rs | 102 +++++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/ssz/src/encode.rs b/ssz/src/encode.rs index 80d07a328c0..b94c36ca5c6 100644 --- a/ssz/src/encode.rs +++ b/ssz/src/encode.rs @@ -40,6 +40,13 @@ impl SszStream { self.buffer.extend_from_slice(&vec); } + /// Append some ssz encoded bytes to the stream without calculating length + /// + /// The raw bytes will be concatenated to the stream. + pub fn append_encoded_raw(&mut self, vec: &Vec) { + self.buffer.extend_from_slice(&vec); + } + /// Append some vector (list) of encodable values to the stream. /// /// The length of the list will be concatenated to the stream, then diff --git a/ssz/src/impl_encode.rs b/ssz/src/impl_encode.rs index 88b4c1edc81..3299cbffec7 100644 --- a/ssz/src/impl_encode.rs +++ b/ssz/src/impl_encode.rs @@ -1,8 +1,11 @@ +extern crate bytes; + use super::{ Encodable, SszStream }; use super::ethereum_types::{ H256, U256 }; +use self::bytes::{ BytesMut, BufMut }; /* * Note: there is a "to_bytes" function for integers @@ -10,40 +13,39 @@ use super::ethereum_types::{ H256, U256 }; * use it instead. */ macro_rules! impl_encodable_for_uint { - ($type: ident) => { + ($type: ident, $bit_size: expr) => { impl Encodable for $type { fn ssz_append(&self, s: &mut SszStream) { - // Number of bits required to represent this integer. - // This could be optimised at the expense of complexity. - let num_bits = { - let mut n = *self; - let mut r: usize = 0; - while n > 0 { - n >>= 1; - r += 1; - } - if r == 0 { 1 } else { r } - }; - // Number of bytes required to represent this bit - let num_bytes = (num_bits + 8 - 1) / 8; - let mut ssz_val: Vec = Vec::with_capacity(num_bytes); - ssz_val.resize(num_bytes, 0); - for i in (0..num_bytes).rev() { - let offset = (num_bytes - i - 1) * 8; - ssz_val[i] = 0_u8 | (self >> offset) as u8 + // Ensure bit size is valid + assert!((0 < $bit_size) && + ($bit_size % 8 == 0) && + (2_u128.pow($bit_size) > *self as u128)); + + // Serialize to bytes + let mut buf = BytesMut::with_capacity($bit_size/8); + + // Match bit size with encoding + match $bit_size { + 8 => buf.put_u8(*self as u8), + 16 => buf.put_u16_be(*self as u16), + 32 => buf.put_u32_be(*self as u32), + 64 => buf.put_u64_be(*self as u64), + _ => { ; } } - s.append_encoded_val(&ssz_val); + + // Append bytes to the SszStream + s.append_encoded_raw(&mut buf.to_vec()); } } } } -impl_encodable_for_uint!(u8); -impl_encodable_for_uint!(u16); -impl_encodable_for_uint!(u32); -impl_encodable_for_uint!(u64); -impl_encodable_for_uint!(usize); +impl_encodable_for_uint!(u8, 8); +impl_encodable_for_uint!(u16, 16); +impl_encodable_for_uint!(u32, 32); +impl_encodable_for_uint!(u64, 64); +impl_encodable_for_uint!(usize, 64); impl Encodable for H256 { fn ssz_append(&self, s: &mut SszStream) { @@ -66,25 +68,25 @@ mod tests { #[test] fn test_ssz_encode_u8() { - let x: u16 = 0; + let x: u8 = 0; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 0]); + assert_eq!(ssz.drain(), vec![0]); - let x: u16 = 1; + let x: u8 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 1]); + assert_eq!(ssz.drain(), vec![1]); - let x: u16 = 100; + let x: u8 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 100]); + assert_eq!(ssz.drain(), vec![100]); - let x: u16 = 255; + let x: u8 = 255; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 255]); + assert_eq!(ssz.drain(), vec![255]); } #[test] @@ -92,22 +94,22 @@ mod tests { let x: u16 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 1]); + assert_eq!(ssz.drain(), vec![0, 1]); let x: u16 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 100]); + assert_eq!(ssz.drain(), vec![0, 100]); let x: u16 = 1 << 8; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 2, 1, 0]); + assert_eq!(ssz.drain(), vec![1, 0]); let x: u16 = 65535; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 2, 255, 255]); + assert_eq!(ssz.drain(), vec![255, 255]); } #[test] @@ -115,27 +117,27 @@ mod tests { let x: u32 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 1]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 1]); let x: u32 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 100]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 100]); let x: u32 = 1 << 16; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 3, 1, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 1, 0, 0]); let x: u32 = 1 << 24; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 4, 1, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![1, 0, 0, 0]); let x: u32 = !0; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 4, 255, 255, 255, 255]); + assert_eq!(ssz.drain(), vec![255, 255, 255, 255]); } #[test] @@ -143,22 +145,22 @@ mod tests { let x: u64 = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 1]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); let x: u64 = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 100]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); let x: u64 = 1 << 32; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 5, 1, 0, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); let x: u64 = !0; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]); + assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); } #[test] @@ -166,21 +168,21 @@ mod tests { let x: usize = 1; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 1]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); let x: usize = 100; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 1, 100]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); let x: usize = 1 << 32; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 5, 1, 0, 0, 0, 0]); + assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); let x: usize = !0; let mut ssz = SszStream::new(); ssz.append(&x); - assert_eq!(ssz.drain(), vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]); + assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); } } From 92ebe5da0ded2b26963250bd46383891fe478a7e Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 15:53:53 +1000 Subject: [PATCH 02/12] Add `decode_ssz` function for general deserialization --- ssz/src/decode.rs | 16 +++++- ssz/src/impl_decode.rs | 116 ++++++++++++++++++++++++++++------------- ssz/src/lib.rs | 2 +- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index d726a58320e..c8b5908edc8 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -10,7 +10,21 @@ pub enum DecodeError { } pub trait Decodable: Sized { - fn ssz_decode(bytes: &[u8]) -> Result; + fn ssz_decode(bytes: &[u8], index: usize) -> Result; +} + +/// Decode the given bytes for the given type +/// +/// The single ssz encoded value will be decoded as the given type at the +/// given index. +pub fn decode_ssz(ssz_bytes: &[u8], index: usize) + -> Result + where T: Decodable +{ + if index >= ssz_bytes.len() { + return Err(DecodeError::OutOfBounds) + } + T::ssz_decode(ssz_bytes, index) } /// Decode the nth element of some ssz list. diff --git a/ssz/src/impl_decode.rs b/ssz/src/impl_decode.rs index 55fdf31e2e8..b17e93a4f69 100644 --- a/ssz/src/impl_decode.rs +++ b/ssz/src/impl_decode.rs @@ -5,22 +5,23 @@ use super::{ macro_rules! impl_decodable_for_uint { ($type: ident, $bit_size: expr) => { impl Decodable for $type { - fn ssz_decode(bytes: &[u8]) + fn ssz_decode(bytes: &[u8], index: usize) -> Result { assert!((0 < $bit_size) & ($bit_size <= 64) & ($bit_size % 8 == 0)); let max_bytes = $bit_size / 8; - if bytes.len() <= max_bytes { + if bytes.len() >= (index + max_bytes) { + let end_bytes = index + max_bytes; let mut result: $type = 0; - for i in 0..bytes.len() { - let offset = (bytes.len() - i - 1) * 8; + for i in index..end_bytes { + let offset = ((index + max_bytes) - i - 1) * 8; result = ((bytes[i] as $type) << offset) | result; }; Ok(result) } else { - Err(DecodeError::TooLong) + Err(DecodeError::TooShort) } } } @@ -37,78 +38,119 @@ impl_decodable_for_uint!(usize, 64); mod tests { use super::super::{ DecodeError, - decode_ssz_list_element, + decode_ssz, }; #[test] fn test_ssz_decode_u16() { - let ssz = vec![0, 0, 1, 0]; - let result: u16 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 0]; + let result: u16 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); - let ssz = vec![0, 0, 1, 16]; - let result: u16 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 16]; + let result: u16 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 16); - let ssz = vec![0, 0, 2, 1, 0]; - let result: u16 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![1, 0]; + let result: u16 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 256); - let ssz = vec![0, 0, 2, 255, 255]; - let result: u16 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![255, 255]; + let result: u16 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 65535); - let ssz = vec![0, 0, 3, 0, 0, 1]; + let ssz = vec![1]; let result: Result = - decode_ssz_list_element(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooLong)); + decode_ssz(&ssz, 0); + assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_u32() { - let ssz = vec![0, 0, 1, 0]; - let result: u32 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 0, 0, 0]; + let result: u32 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); - let ssz = vec![0, 0, 4, 255, 255, 255, 255]; - let result: u32 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 0, 1, 0]; + let result: u32 = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(result, 256); + + let ssz = vec![255, 255, 255, 0, 0, 1, 0]; + let result: u32 = decode_ssz(&ssz, 3).unwrap(); + assert_eq!(result, 256); + + let ssz = vec![0,200, 1, 0]; + let result: u32 = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(result, 13107456); + + let ssz = vec![255, 255, 255, 255]; + let result: u32 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 4294967295); - let ssz = vec![0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + let ssz = vec![0, 0, 1]; let result: Result = - decode_ssz_list_element(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooLong)); + decode_ssz(&ssz, 0); + assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_u64() { - let ssz = vec![0, 0, 1, 0]; - let result: u64 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; + let result: u64 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); - let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; - let result: u64 = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; + let result: u64 = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 18446744073709551615); - let ssz = vec![0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + let ssz = vec![255, 255, 255, 0, 0, 0, 0, 0, 0, 0]; + let result: u64 = decode_ssz(&ssz, 2).unwrap(); + assert_eq!(result, 18374686479671623680); + + let ssz = vec![0,0,0,0,0,0,0]; let result: Result = - decode_ssz_list_element(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooLong)); + decode_ssz(&ssz, 0); + assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_ssz_decode_usize() { - let ssz = vec![0, 0, 1, 0]; - let result: usize = decode_ssz_list_element(&ssz, 0).unwrap(); + let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; + let result: usize = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; - let result: usize = decode_ssz_list_element(&ssz, 0).unwrap(); + let result: usize = decode_ssz(&ssz, 3).unwrap(); + assert_eq!(result, 18446744073709551615); + + let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; + let result: usize = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 18446744073709551615); - let ssz = vec![0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + let ssz = vec![0, 0, 0, 0, 0, 0, 1]; let result: Result = - decode_ssz_list_element(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooLong)); + decode_ssz(&ssz, 0); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + fn test_decode_ssz_bounds() { + let err: Result = decode_ssz( + &vec![1], + 2 + ); + assert_eq!(err, Err(DecodeError::OutOfBounds)); + + let err: Result = decode_ssz( + &vec![0, 0, 0, 0], + 3 + ); + assert_eq!(err, Err(DecodeError::TooShort)); + + let result: u16 = decode_ssz( + &vec![0,0,0,0,1], + 3 + ).unwrap(); + assert_eq!(result, 1); } } diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index b5091c1fb34..7fa26420676 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -18,7 +18,7 @@ mod impl_decode; pub use decode::{ Decodable, DecodeError, - decode_ssz_list_element, + decode_ssz, }; pub use encode::{ Encodable, From 6802bbf4073fcc857a47057b8c85e341211ff51d Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 15:59:29 +1000 Subject: [PATCH 03/12] Remove `decode_ssz_list_element` unused function. --- ssz/src/decode.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index c8b5908edc8..7cc4c249657 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -27,17 +27,6 @@ pub fn decode_ssz(ssz_bytes: &[u8], index: usize) T::ssz_decode(ssz_bytes, index) } -/// Decode the nth element of some ssz list. -/// -/// A single ssz encoded value can be considered a list of -/// one element, so this function will work on it too. -pub fn decode_ssz_list_element(ssz_bytes: &[u8], n: usize) - -> Result - where T: Decodable -{ - T::ssz_decode(nth_value(ssz_bytes, n)?) -} - /// Return the nth value in some ssz encoded list. /// /// The four-byte length prefix is not included in the return. From 94d21c78cd1a29ed7e5d6335447d5d5b8c06f3dd Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 18:47:25 +1000 Subject: [PATCH 04/12] Add new index to return of decode --- ssz/src/decode.rs | 34 +++++---------------- ssz/src/encode.rs | 14 ++++----- ssz/src/impl_decode.rs | 68 ++++++++++++++++++++++++++---------------- ssz/src/lib.rs | 2 +- 4 files changed, 57 insertions(+), 61 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index 7cc4c249657..18988457f41 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -10,7 +10,7 @@ pub enum DecodeError { } pub trait Decodable: Sized { - fn ssz_decode(bytes: &[u8], index: usize) -> Result; + fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError>; } /// Decode the given bytes for the given type @@ -18,7 +18,7 @@ pub trait Decodable: Sized { /// The single ssz encoded value will be decoded as the given type at the /// given index. pub fn decode_ssz(ssz_bytes: &[u8], index: usize) - -> Result + -> Result<(T, usize), DecodeError> where T: Decodable { if index >= ssz_bytes.len() { @@ -79,24 +79,24 @@ mod tests { #[test] fn test_ssz_decode_length() { let decoded = decode_length( - &vec![0, 0, 1], + &vec![0, 0, 0, 1], LENGTH_BYTES); assert_eq!(decoded.unwrap(), 1); let decoded = decode_length( - &vec![0, 1, 0], + &vec![0, 0, 1, 0], LENGTH_BYTES); assert_eq!(decoded.unwrap(), 256); let decoded = decode_length( - &vec![0, 1, 255], + &vec![0, 0, 1, 255], LENGTH_BYTES); assert_eq!(decoded.unwrap(), 511); let decoded = decode_length( - &vec![255, 255, 255], + &vec![255, 255, 255, 255], LENGTH_BYTES); - assert_eq!(decoded.unwrap(), 16777215); + assert_eq!(decoded.unwrap(), 4294967295); } #[test] @@ -115,24 +115,4 @@ mod tests { assert_eq!(i, decoded); } } - - #[test] - fn test_ssz_nth_value() { - let ssz = vec![0, 0, 1, 0]; - let result = nth_value(&ssz, 0).unwrap(); - assert_eq!(result, vec![0].as_slice()); - - let ssz = vec![0, 0, 4, 1, 2, 3, 4]; - let result = nth_value(&ssz, 0).unwrap(); - assert_eq!(result, vec![1, 2, 3, 4].as_slice()); - - let ssz = vec![0, 0, 1, 0, 0, 0, 1, 1]; - let result = nth_value(&ssz, 1).unwrap(); - assert_eq!(result, vec![1].as_slice()); - - let mut ssz = vec![0, 1, 255]; - ssz.append(&mut vec![42; 511]); - let result = nth_value(&ssz, 0).unwrap(); - assert_eq!(result, vec![42; 511].as_slice()); - } } diff --git a/ssz/src/encode.rs b/ssz/src/encode.rs index b94c36ca5c6..186c7582d83 100644 --- a/ssz/src/encode.rs +++ b/ssz/src/encode.rs @@ -96,29 +96,29 @@ mod tests { fn test_encode_length_4_bytes() { assert_eq!( encode_length(0, LENGTH_BYTES), - vec![0; 3] + vec![0; 4] ); assert_eq!( encode_length(1, LENGTH_BYTES), - vec![0, 0, 1] + vec![0, 0, 0, 1] ); assert_eq!( encode_length(255, LENGTH_BYTES), - vec![0, 0, 255] + vec![0, 0, 0, 255] ); assert_eq!( encode_length(256, LENGTH_BYTES), - vec![0, 1, 0] + vec![0, 0, 1, 0] ); assert_eq!( - encode_length(16777215, LENGTH_BYTES), // 2^(3*8) - 1 - vec![255, 255, 255] + encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1 + vec![255, 255, 255, 255] ); } #[test] #[should_panic] fn test_encode_length_4_bytes_panic() { - encode_length(16777216, LENGTH_BYTES); // 2^(3*8) + encode_length(4294967296, LENGTH_BYTES); // 2^(3*8) } } diff --git a/ssz/src/impl_decode.rs b/ssz/src/impl_decode.rs index b17e93a4f69..5dcc4104af4 100644 --- a/ssz/src/impl_decode.rs +++ b/ssz/src/impl_decode.rs @@ -6,7 +6,7 @@ macro_rules! impl_decodable_for_uint { ($type: ident, $bit_size: expr) => { impl Decodable for $type { fn ssz_decode(bytes: &[u8], index: usize) - -> Result + -> Result<(Self, usize), DecodeError> { assert!((0 < $bit_size) & ($bit_size <= 64) & @@ -19,7 +19,7 @@ macro_rules! impl_decodable_for_uint { let offset = ((index + max_bytes) - i - 1) * 8; result = ((bytes[i] as $type) << offset) | result; }; - Ok(result) + Ok((result, end_bytes)) } else { Err(DecodeError::TooShort) } @@ -44,23 +44,28 @@ mod tests { #[test] fn test_ssz_decode_u16() { let ssz = vec![0, 0]; - let result: u16 = decode_ssz(&ssz, 0).unwrap(); + + let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); + assert_eq!(index, 2); let ssz = vec![0, 16]; - let result: u16 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 16); + assert_eq!(index, 2); let ssz = vec![1, 0]; - let result: u16 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 256); + assert_eq!(index, 2); let ssz = vec![255, 255]; - let result: u16 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 2); assert_eq!(result, 65535); let ssz = vec![1]; - let result: Result = + let result: Result<(u16, usize), DecodeError> = decode_ssz(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } @@ -68,27 +73,32 @@ mod tests { #[test] fn test_ssz_decode_u32() { let ssz = vec![0, 0, 0, 0]; - let result: u32 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); assert_eq!(result, 0); + assert_eq!(index, 4); let ssz = vec![0, 0, 1, 0]; - let result: u32 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 4); assert_eq!(result, 256); let ssz = vec![255, 255, 255, 0, 0, 1, 0]; - let result: u32 = decode_ssz(&ssz, 3).unwrap(); + let (result, index): (u32, usize) = decode_ssz(&ssz, 3).unwrap(); + assert_eq!(index, 7); assert_eq!(result, 256); let ssz = vec![0,200, 1, 0]; - let result: u32 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 4); assert_eq!(result, 13107456); let ssz = vec![255, 255, 255, 255]; - let result: u32 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 4); assert_eq!(result, 4294967295); let ssz = vec![0, 0, 1]; - let result: Result = + let result: Result<(u32, usize), DecodeError> = decode_ssz(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } @@ -96,19 +106,22 @@ mod tests { #[test] fn test_ssz_decode_u64() { let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let result: u64 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 8); assert_eq!(result, 0); let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; - let result: u64 = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 8); assert_eq!(result, 18446744073709551615); - let ssz = vec![255, 255, 255, 0, 0, 0, 0, 0, 0, 0]; - let result: u64 = decode_ssz(&ssz, 2).unwrap(); + let ssz = vec![0, 0, 8, 255, 0, 0, 0, 0, 0, 0, 0]; + let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap(); + assert_eq!(index, 11); assert_eq!(result, 18374686479671623680); let ssz = vec![0,0,0,0,0,0,0]; - let result: Result = + let result: Result<(u64, usize), DecodeError> = decode_ssz(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } @@ -116,32 +129,35 @@ mod tests { #[test] fn test_ssz_decode_usize() { let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let result: usize = decode_ssz(&ssz, 0).unwrap(); + let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 8); assert_eq!(result, 0); let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; - let result: usize = decode_ssz(&ssz, 3).unwrap(); + let (result, index): (usize, usize) = decode_ssz(&ssz, 3).unwrap(); + assert_eq!(index, 11); assert_eq!(result, 18446744073709551615); - let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; - let result: usize = decode_ssz(&ssz, 0).unwrap(); + let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; + let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); + assert_eq!(index, 8); assert_eq!(result, 18446744073709551615); let ssz = vec![0, 0, 0, 0, 0, 0, 1]; - let result: Result = + let result: Result<(usize, usize), DecodeError> = decode_ssz(&ssz, 0); assert_eq!(result, Err(DecodeError::TooShort)); } #[test] fn test_decode_ssz_bounds() { - let err: Result = decode_ssz( + let err: Result<(u16, usize), DecodeError> = decode_ssz( &vec![1], 2 ); assert_eq!(err, Err(DecodeError::OutOfBounds)); - let err: Result = decode_ssz( + let err: Result<(u16,usize), DecodeError> = decode_ssz( &vec![0, 0, 0, 0], 3 ); @@ -150,7 +166,7 @@ mod tests { let result: u16 = decode_ssz( &vec![0,0,0,0,1], 3 - ).unwrap(); + ).unwrap().0; assert_eq!(result, 1); } } diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index 7fa26420676..6a0fd66ce38 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -25,4 +25,4 @@ pub use encode::{ SszStream, }; -pub const LENGTH_BYTES: usize = 3; +pub const LENGTH_BYTES: usize = 4; From 199b7490b340f0aabc1a875a2e17dc456d81aa4d Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 18:48:09 +1000 Subject: [PATCH 05/12] Begin `decode_ssz_list` for serialized lists of elements --- ssz/src/decode.rs | 60 +++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index 18988457f41..0c6a3db3474 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -27,31 +27,45 @@ pub fn decode_ssz(ssz_bytes: &[u8], index: usize) T::ssz_decode(ssz_bytes, index) } -/// Return the nth value in some ssz encoded list. +/// Decode a vector (list) of encoded bytes. /// -/// The four-byte length prefix is not included in the return. -/// -/// A single ssz encoded value can be considered a list of -/// one element, so this function will work on it too. -fn nth_value(ssz_bytes: &[u8], n: usize) - -> Result<&[u8], DecodeError> +/// Each element in the list will be decoded and placed into the vector. +pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) + -> Result<(Vec, usize), DecodeError> + where T: Decodable { - let mut c: usize = 0; - for i in 0..(n + 1) { - let length = decode_length(&ssz_bytes[c..], LENGTH_BYTES)?; - let next = c + LENGTH_BYTES + length; - - if i == n { - return Ok(&ssz_bytes[c + LENGTH_BYTES..next]); - } else { - if next >= ssz_bytes.len() { - return Err(DecodeError::OutOfBounds); - } else { - c = next; - } - } - } - Err(DecodeError::OutOfBounds) + + if index + LENGTH_BYTES > ssz_bytes.len() { + return Err(DecodeError::OutOfBounds); + }; + + // get the length + let mut serialized_length = match decode_length(ssz_bytes, LENGTH_BYTES) { + Err(v) => return Err(v), + Ok(v) => v, + }; + + let final_len: usize = index + LENGTH_BYTES + serialized_length; + + if final_len > ssz_bytes.len() { + return Err(DecodeError::OutOfBounds); + }; + + let mut tmp_index = index + LENGTH_BYTES; + let mut res_vec: Vec = Vec::new(); + + while tmp_index < final_len { + match T::ssz_decode(ssz_bytes, tmp_index) { + Err(v) => return Err(v), + Ok(v) => { + tmp_index = v.1; + res_vec.push(v.0); + }, + }; + + }; + + Ok((res_vec, final_len)) } /// Given some number of bytes, interpret the first four From 0fed1997a24c6f450b5433a16e9c9212a6fde616 Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 23:19:45 +1000 Subject: [PATCH 06/12] Add 'decode_ssz_list', update 'decode_length' to take index --- ssz/src/decode.rs | 90 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index 0c6a3db3474..15c053bcf08 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -36,11 +36,11 @@ pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) { if index + LENGTH_BYTES > ssz_bytes.len() { - return Err(DecodeError::OutOfBounds); + return Err(DecodeError::TooShort); }; // get the length - let mut serialized_length = match decode_length(ssz_bytes, LENGTH_BYTES) { + let serialized_length = match decode_length(ssz_bytes, index, LENGTH_BYTES) { Err(v) => return Err(v), Ok(v) => v, }; @@ -48,7 +48,7 @@ pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) let final_len: usize = index + LENGTH_BYTES + serialized_length; if final_len > ssz_bytes.len() { - return Err(DecodeError::OutOfBounds); + return Err(DecodeError::TooShort); }; let mut tmp_index = index + LENGTH_BYTES; @@ -71,15 +71,15 @@ pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) /// Given some number of bytes, interpret the first four /// bytes as a 32-bit big-endian integer and return the /// result. -fn decode_length(bytes: &[u8], length_bytes: usize) +fn decode_length(bytes: &[u8], index: usize, length_bytes: usize) -> Result { if bytes.len() < length_bytes { return Err(DecodeError::TooShort); }; let mut len: usize = 0; - for i in 0..length_bytes { - let offset = (length_bytes - i - 1) * 8; + for i in index..index+length_bytes { + let offset = (index+length_bytes - i - 1) * 8; len = ((bytes[i] as usize) << offset) | len; }; Ok(len) @@ -94,21 +94,25 @@ mod tests { fn test_ssz_decode_length() { let decoded = decode_length( &vec![0, 0, 0, 1], + 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 1); let decoded = decode_length( &vec![0, 0, 1, 0], + 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 256); let decoded = decode_length( &vec![0, 0, 1, 255], + 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 511); let decoded = decode_length( &vec![255, 255, 255, 255], + 0, LENGTH_BYTES); assert_eq!(decoded.unwrap(), 4294967295); } @@ -125,8 +129,82 @@ mod tests { for i in params { let decoded = decode_length( &encode_length(i, LENGTH_BYTES), + 0, LENGTH_BYTES).unwrap(); assert_eq!(i, decoded); } } + + #[test] + fn test_decode_ssz_list() { + // u16 + let v: Vec = vec![10, 10, 10, 10]; + let decoded: (Vec, usize) = decode_ssz_list( + &vec![0, 0, 0, 8, 0, 10, 0, 10, 0, 10, 0, 10], + 0 + ).unwrap(); + + assert_eq!(decoded.0, v); + assert_eq!(decoded.1, 12); + + // u32 + let v: Vec = vec![10, 10, 10, 10]; + let decoded: (Vec, usize) = decode_ssz_list( + &vec![ + 0, 0, 0, 16, + 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10 + ], + 0 + ).unwrap(); + assert_eq!(decoded.0, v); + assert_eq!(decoded.1, 20); + + + // u64 + let v: Vec = vec![10,10,10,10]; + let decoded: (Vec, usize) = decode_ssz_list( + &vec![0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 10, + ], + 0 + ).unwrap(); + assert_eq!(decoded.0, v); + assert_eq!(decoded.1, 36); + + // Check that it can accept index + let v: Vec = vec![15,15,15,15]; + let decoded: (Vec, usize) = decode_ssz_list( + &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 15, + ], + 10 + ).unwrap(); + assert_eq!(decoded.0, v); + assert_eq!(decoded.1, 46); + + // Check that length > bytes throws error + let decoded: Result<(Vec, usize), DecodeError> = decode_ssz_list( + &vec![0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, 0, 15, + ], + 0 + ); + assert_eq!(decoded, Err(DecodeError::TooShort)); + + // Check that incorrect index throws error + let decoded: Result<(Vec, usize), DecodeError> = decode_ssz_list( + &vec![ + 0, 0, 0, 0, 0, 0, 0, 15, + ], + 16 + ); + assert_eq!(decoded, Err(DecodeError::TooShort)); + } } From 1f74200129279a9227a8c290bb8db92f4808f495 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 19 Sep 2018 14:48:42 +1000 Subject: [PATCH 07/12] Change visibility so you can export decode_length --- ssz/src/decode.rs | 2 +- ssz/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index 15c053bcf08..9d4132be8d2 100644 --- a/ssz/src/decode.rs +++ b/ssz/src/decode.rs @@ -71,7 +71,7 @@ pub fn decode_ssz_list(ssz_bytes: &[u8], index: usize) /// Given some number of bytes, interpret the first four /// bytes as a 32-bit big-endian integer and return the /// result. -fn decode_length(bytes: &[u8], index: usize, length_bytes: usize) +pub fn decode_length(bytes: &[u8], index: usize, length_bytes: usize) -> Result { if bytes.len() < length_bytes { diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index 6a0fd66ce38..d75072801f8 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -10,8 +10,9 @@ extern crate bytes; extern crate ethereum_types; +pub mod decode; + mod encode; -mod decode; mod impl_encode; mod impl_decode; From 53692caeb33bae580fcb8e1ca4d98a5bba40e69a Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 19 Sep 2018 17:44:12 +1000 Subject: [PATCH 08/12] Roughly implement ssz list encoding --- ssz/src/encode.rs | 36 ++++++++++++++++++++++++++++++++---- ssz/src/lib.rs | 1 + 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/ssz/src/encode.rs b/ssz/src/encode.rs index 186c7582d83..d5095af6b9a 100644 --- a/ssz/src/encode.rs +++ b/ssz/src/encode.rs @@ -1,4 +1,12 @@ -use super::LENGTH_BYTES; +use super::{ + LENGTH_BYTES, + MAX_LIST_SIZE, +}; + +#[derive(Debug)] +pub enum EncodeError { + ListTooLong, +} pub trait Encodable { fn ssz_append(&self, s: &mut SszStream); @@ -52,11 +60,19 @@ impl SszStream { /// The length of the list will be concatenated to the stream, then /// each item in the vector will be encoded and concatenated. pub fn append_vec(&mut self, vec: &Vec) + -> Result<(), EncodeError> where E: Encodable { - self.buffer.extend_from_slice(&encode_length(vec.len(), LENGTH_BYTES)); - for v in vec { - v.ssz_append(self); + let mut list_stream = SszStream::new(); + for item in vec { + item.ssz_append(&mut list_stream); + } + let list_ssz = list_stream.drain(); + if list_ssz.len() <= MAX_LIST_SIZE { + self.append_encoded_val(&list_ssz); + Ok(()) + } else { + Err(EncodeError::ListTooLong) } } @@ -121,4 +137,16 @@ mod tests { fn test_encode_length_4_bytes_panic() { encode_length(4294967296, LENGTH_BYTES); // 2^(3*8) } + + #[test] + fn test_encode_list() { + let test_vec: Vec = vec![256; 12]; + let mut stream = SszStream::new(); + stream.append_vec(&test_vec).unwrap(); + let ssz = stream.drain(); + + assert_eq!(ssz.len(), 4 + (12 * 2)); + assert_eq!(ssz[0..4], *vec![0, 0, 0, 24]); + assert_eq!(ssz[4..6], *vec![1, 0]); + } } diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index d75072801f8..0fcfb21dbd5 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -27,3 +27,4 @@ pub use encode::{ }; pub const LENGTH_BYTES: usize = 4; +pub const MAX_LIST_SIZE : usize = 1 << (4 * 8); From e88686e4f46e301114aba692364a90838a4beba6 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 19 Sep 2018 17:48:52 +1000 Subject: [PATCH 09/12] Remove Result from list encoding, panic instead --- ssz/src/encode.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ssz/src/encode.rs b/ssz/src/encode.rs index d5095af6b9a..5080924ccf0 100644 --- a/ssz/src/encode.rs +++ b/ssz/src/encode.rs @@ -60,20 +60,13 @@ impl SszStream { /// The length of the list will be concatenated to the stream, then /// each item in the vector will be encoded and concatenated. pub fn append_vec(&mut self, vec: &Vec) - -> Result<(), EncodeError> where E: Encodable { let mut list_stream = SszStream::new(); for item in vec { item.ssz_append(&mut list_stream); } - let list_ssz = list_stream.drain(); - if list_ssz.len() <= MAX_LIST_SIZE { - self.append_encoded_val(&list_ssz); - Ok(()) - } else { - Err(EncodeError::ListTooLong) - } + self.append_encoded_val(&list_stream.drain()); } /// Consume the stream and return the underlying bytes. @@ -142,7 +135,7 @@ mod tests { fn test_encode_list() { let test_vec: Vec = vec![256; 12]; let mut stream = SszStream::new(); - stream.append_vec(&test_vec).unwrap(); + stream.append_vec(&test_vec); let ssz = stream.drain(); assert_eq!(ssz.len(), 4 + (12 * 2)); From 8439094a8d5b765d729753396e4048786a6e1d3d Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 21 Sep 2018 18:57:33 +1000 Subject: [PATCH 10/12] Fix H256 encoding, remove U256 encoding Addresses #20 --- ssz/src/impl_encode.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ssz/src/impl_encode.rs b/ssz/src/impl_encode.rs index 3299cbffec7..392f8667e02 100644 --- a/ssz/src/impl_encode.rs +++ b/ssz/src/impl_encode.rs @@ -4,7 +4,7 @@ use super::{ Encodable, SszStream }; -use super::ethereum_types::{ H256, U256 }; +use super::ethereum_types::H256; use self::bytes::{ BytesMut, BufMut }; /* @@ -49,15 +49,7 @@ impl_encodable_for_uint!(usize, 64); impl Encodable for H256 { fn ssz_append(&self, s: &mut SszStream) { - s.append_encoded_val(&self.to_vec()); - } -} - -impl Encodable for U256 { - fn ssz_append(&self, s: &mut SszStream) { - let mut a = [0; 32]; - self.to_big_endian(&mut a); - s.append_encoded_val(&a.to_vec()); + s.append_encoded_raw(&self.to_vec()); } } @@ -66,6 +58,14 @@ impl Encodable for U256 { mod tests { use super::*; + #[test] + fn test_ssz_encode_h256() { + let h = H256::zero(); + let mut ssz = SszStream::new(); + ssz.append(&h); + assert_eq!(ssz.drain(), vec![0; 32]); + } + #[test] fn test_ssz_encode_u8() { let x: u8 = 0; From 8b4970ed5135495fe7bd5d695ccfa09f661c9acf Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 22 Sep 2018 12:11:10 +1000 Subject: [PATCH 11/12] Implement SSZ decode for H256 --- Cargo.toml | 3 ++- ssz/src/impl_decode.rs | 47 ++++++++++++++++++++++++++++++++++++++++++ ssz/src/lib.rs | 1 + 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ae9194004c7..778df551d01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ boolean-bitfield = { path = "boolean-bitfield" } bytes = "" crypto-mac = "^0.6.2" clap = "2.32.0" -ethereum-types = "" +dirs = "1.0.3" +ethereum-types = "0.4.0" futures = "0.1.23" network-libp2p = { path = "network-libp2p" } rand = "0.3" diff --git a/ssz/src/impl_decode.rs b/ssz/src/impl_decode.rs index 5dcc4104af4..bbcb9d863fa 100644 --- a/ssz/src/impl_decode.rs +++ b/ssz/src/impl_decode.rs @@ -1,7 +1,10 @@ +use super::ethereum_types::H256; use super::{ DecodeError, Decodable, }; + + macro_rules! impl_decodable_for_uint { ($type: ident, $bit_size: expr) => { impl Decodable for $type { @@ -33,14 +36,58 @@ impl_decodable_for_uint!(u32, 32); impl_decodable_for_uint!(u64, 64); impl_decodable_for_uint!(usize, 64); +impl Decodable for H256 { + fn ssz_decode(bytes: &[u8], index: usize) + -> Result<(Self, usize), DecodeError> + { + if bytes.len() < 32 { + return Err(DecodeError::TooShort) + } + else if bytes.len() - 32 < index { + return Err(DecodeError::TooShort) + } + else { + return Ok((H256::from(&bytes[index..(index + 32)]), + index + 32)); + } + } +} #[cfg(test)] mod tests { + use super::*; use super::super::{ DecodeError, decode_ssz, }; + #[test] + fn test_ssz_decode_h256() { + /* + * Input is exact length + */ + let input = vec![42_u8; 32]; + let (decoded, i) = H256::ssz_decode(&input, 0).unwrap(); + assert_eq!(decoded.to_vec(), input); + assert_eq!(i, 32); + + /* + * Input is too long + */ + let mut input = vec![42_u8; 32]; + input.push(12); + let (decoded, i) = H256::ssz_decode(&input, 0).unwrap(); + assert_eq!(decoded.to_vec()[..], input[0..32]); + assert_eq!(i, 32); + + /* + * Input is too short + */ + let input = vec![42_u8; 31]; + let res = H256::ssz_decode(&input, 0); + assert_eq!(res, Err(DecodeError::TooShort)); + } + #[test] fn test_ssz_decode_u16() { let ssz = vec![0, 0]; diff --git a/ssz/src/lib.rs b/ssz/src/lib.rs index 0fcfb21dbd5..bf0de9262ac 100644 --- a/ssz/src/lib.rs +++ b/ssz/src/lib.rs @@ -20,6 +20,7 @@ pub use decode::{ Decodable, DecodeError, decode_ssz, + decode_ssz_list, }; pub use encode::{ Encodable, From 235a04955560121c635ed4318dc04ff7e9013558 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 22 Sep 2018 12:19:43 +1000 Subject: [PATCH 12/12] Specify ethereum-types version in SSZ --- ssz/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssz/Cargo.toml b/ssz/Cargo.toml index 0500ab3c5c3..aa4dc5d72cc 100644 --- a/ssz/Cargo.toml +++ b/ssz/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Paul Hauner "] [dependencies] bytes = "0.4.9" -ethereum-types = "" +ethereum-types = "0.4.0"