From cc1fc5c0cc07d2f0ac15a3fbcc76005545caafc1 Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Mon, 17 Sep 2018 16:54:51 +1000 Subject: [PATCH 1/6] 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 80d07a328..b94c36ca5 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 88b4c1edc..3299cbffe 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 2/6] 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 d726a5832..c8b5908ed 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 55fdf31e2..b17e93a4f 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![0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 1]; + 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, 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 b5091c1fb..7fa264206 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 3/6] 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 c8b5908ed..7cc4c2496 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 4/6] 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 7cc4c2496..18988457f 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 b94c36ca5..186c7582d 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 b17e93a4f..5dcc4104a 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 7fa264206..6a0fd66ce 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 5/6] Begin `decode_ssz_list` for serialized lists of elements --- ssz/src/decode.rs | 58 +++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/ssz/src/decode.rs b/ssz/src/decode.rs index 18988457f..0c6a3db34 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 6/6] 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 0c6a3db34..15c053bcf 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)); + } }