From 92ebe5da0ded2b26963250bd46383891fe478a7e Mon Sep 17 00:00:00 2001 From: NatoliChris Date: Tue, 18 Sep 2018 15:53:53 +1000 Subject: [PATCH] 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 d726a58320..c8b5908edc 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 55fdf31e2e..b17e93a4f6 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 b5091c1fb3..7fa2642067 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,