From 3f9430ddffb4722604c791b31db38e0aa7baedf9 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 3 May 2019 11:05:51 +1000 Subject: [PATCH] Add partial progress on sos --- eth2/utils/ssz2/src/decode.rs | 28 +- eth2/utils/ssz2/src/decode/impls.rs | 572 ++++++++++++++++++++++++++++ eth2/utils/ssz2/src/encode/impls.rs | 58 ++- eth2/utils/ssz2/src/impl_decode.rs | 306 --------------- eth2/utils/ssz2/src/lib.rs | 2 + eth2/utils/ssz2/tests/tests.rs | 22 ++ 6 files changed, 658 insertions(+), 330 deletions(-) create mode 100644 eth2/utils/ssz2/src/decode/impls.rs delete mode 100644 eth2/utils/ssz2/src/impl_decode.rs create mode 100644 eth2/utils/ssz2/tests/tests.rs diff --git a/eth2/utils/ssz2/src/decode.rs b/eth2/utils/ssz2/src/decode.rs index 7ed6fe4916..7481565f15 100644 --- a/eth2/utils/ssz2/src/decode.rs +++ b/eth2/utils/ssz2/src/decode.rs @@ -1,16 +1,33 @@ -use super::LENGTH_BYTES; +use super::*; + +mod impls; #[derive(Debug, PartialEq)] pub enum DecodeError { - TooShort, - TooLong, - Invalid, + // BytesTooShort { given: usize, expected: usize }, + // BytesTooLong { given: usize, expected: usize }, + InvalidByteLength { len: usize, expected: usize }, + InvalidLengthPrefix { len: usize, expected: usize }, + BytesInvalid(String), } pub trait Decodable: Sized { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError>; + fn is_ssz_fixed_len() -> bool; + + /// The number of bytes this object occupies in the fixed-length portion of the SSZ bytes. + /// + /// By default, this is set to `BYTES_PER_LENGTH_OFFSET` which is suitable for variable length + /// objects, but not fixed-length objects. Fixed-length objects _must_ return a value which + /// represents their length. + fn ssz_fixed_len() -> usize { + BYTES_PER_LENGTH_OFFSET + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result; } +/* + /// Decode the given bytes for the given type /// /// The single ssz encoded value/container/list will be decoded as the given type, @@ -213,3 +230,4 @@ mod tests { assert_eq!(decoded, Err(DecodeError::TooShort)); } } +*/ diff --git a/eth2/utils/ssz2/src/decode/impls.rs b/eth2/utils/ssz2/src/decode/impls.rs new file mode 100644 index 0000000000..22ab0d940e --- /dev/null +++ b/eth2/utils/ssz2/src/decode/impls.rs @@ -0,0 +1,572 @@ +use super::*; + +macro_rules! impl_decodable_for_uint { + ($type: ident, $bit_size: expr) => { + impl Decodable for $type { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $bit_size / 8 + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = ::ssz_fixed_len(); + + if len != expected { + Err(DecodeError::InvalidByteLength { len, expected }) + } else { + let mut array: [u8; $bit_size / 8] = std::default::Default::default(); + array.clone_from_slice(bytes); + + Ok(Self::from_le_bytes(array)) + } + } + } + }; +} + +impl_decodable_for_uint!(u16, 16); +impl_decodable_for_uint!(u32, 32); +impl_decodable_for_uint!(u64, 64); +impl_decodable_for_uint!(usize, 64); + +impl Decodable for Vec { + fn is_ssz_fixed_len() -> bool { + false + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + if bytes.len() == 0 { + return Ok(vec![]); + } + + if T::is_ssz_fixed_len() { + Ok(bytes + .chunks(T::ssz_fixed_len()) + .map(|chunk| T::from_ssz_bytes(chunk)) + .collect::>()?) + } else { + let (fixed, variable) = bytes.split_at(read_length(bytes)?); + + dbg!(fixed); + dbg!(variable); + + let num_elems = fixed.len() / BYTES_PER_LENGTH_OFFSET; + + dbg!(num_elems); + + let mut offset = 0; + + let mut values = vec![]; + + for i in 1..=num_elems { + let chunk = &bytes[(i - 1) * BYTES_PER_LENGTH_OFFSET..i * BYTES_PER_LENGTH_OFFSET]; + + dbg!(offset); + + let end = offset + decode_length(chunk)?; + let slice = &variable[offset..end]; + offset += end; + + values.push(T::from_ssz_bytes(slice)?); + + if i == num_elems { + let slice = &variable[offset..]; + dbg!(slice); + values.push(T::from_ssz_bytes(slice)?) + } + } + + Ok(values) + + /* + fixed + .chunks(BYTES_PER_LENGTH_OFFSET) + .skip(1) + .map(|chunk| { + let start = offset; + offset += decode_length(chunk)?; + Ok(start..offset) + }) + .chain(vec![Ok(offset..variable.len())].into_iter()) + .map(|range| T::from_ssz_bytes(&variable[range?])) + .collect() + */ + + /* + for i in 1..=num_elems { + let chunk = &bytes[i * BYTES_PER_LENGTH_OFFSET..(i + 1) * BYTES_PER_LENGTH_OFFSET]; + + let end = offset + decode_length(chunk)?; + let slice = &variable[offset..end]; + offset += end; + + values.push(T::from_ssz_bytes(slice)?); + + if i == num_elems { + let slice = &variable[offset..]; + values.push(T::from_ssz_bytes(slice)?) + } + } + + */ + + /* + (0..num_elems) + .into_iter() + .skip(1) + .map(|(i, chunk)| { + let end = offset + decode_length(chunk)?; + let slice = &bytes[offset..end]; + offset += end; + + T::from_ssz_bytes(slice) + + if i == num_elems { + let slice = &bytes[offset..]; + T::from_ssz_bytes(slice) + } + }) + .collect() + + fixed + .chunks(BYTES_PER_LENGTH_OFFSET) + .skip(1) + .enumerate() + .map(|(i, chunk)| { + let end = offset + decode_length(chunk)?; + let slice = &bytes[offset..end]; + offset += end; + + T::from_ssz_bytes(slice) + }) + .collect() + + + fixed + .chunks(BYTES_PER_LENGTH_OFFSET) + .skip(1) + .map(|chunk| { + let end = offset + decode_length(chunk)?; + let slice = &bytes[offset..end]; + offset += end; + + T::from_ssz_bytes(slice) + }) + .collect() + + + let mut i = 0; + // let mut values = vec![]; + + bytes + .get(0..offset) + .ok_or_else(|| DecodeError::InvalidByteLength { + expected: offset, + len: bytes.len(), + })? + .chunks(BYTES_PER_LENGTH_OFFSET) + .skip(1) + .map(|chunk| { + let end = offset + decode_length(chunk)?; + let slice = &bytes[offset..end]; + offset += end; + + T::from_ssz_bytes(slice) + }) + .collect() + + // .collect::, DecodeError>>()?; + + let (fixed, variable) = bytes.split_at(read_length(bytes)?); + + let mut offset = decode_length(); + */ + + //panic!("TODO") + } + } +} + +/// Reads a `BYTES_PER_LENGTH_OFFSET`-byte length from `bytes`, where `bytes.len() >= +/// BYTES_PER_LENGTH_OFFSET`. +fn read_length(bytes: &[u8]) -> Result { + decode_length(bytes.get(0..BYTES_PER_LENGTH_OFFSET).ok_or_else(|| { + DecodeError::InvalidLengthPrefix { + len: bytes.len(), + expected: BYTES_PER_LENGTH_OFFSET, + } + })?) +} + +/// Decode bytes as a little-endian usize, returning an `Err` if `bytes.len() != +/// BYTES_PER_LENGTH_OFFSET`. +pub fn decode_length(bytes: &[u8]) -> Result { + let len = bytes.len(); + let expected = BYTES_PER_LENGTH_OFFSET; + + if len != expected { + Err(DecodeError::InvalidLengthPrefix { len, expected }) + } else { + let mut array: [u8; BYTES_PER_LENGTH_OFFSET] = std::default::Default::default(); + array.clone_from_slice(bytes); + + Ok(u32::from_le_bytes(array) as usize) + } +} + +/* +use super::decode::decode_ssz_list; +use super::ethereum_types::{Address, H256}; +use super::{Decodable, DecodeError}; + +macro_rules! impl_decodable_for_uint { + ($type: ident, $bit_size: expr) => { + impl Decodable for $type { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + assert!((0 < $bit_size) & ($bit_size <= 64) & ($bit_size % 8 == 0)); + let max_bytes = $bit_size / 8; + if bytes.len() >= (index + max_bytes) { + let end_bytes = index + max_bytes; + let mut result: $type = 0; + for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) { + let offset = (i - index) * 8; + result |= ($type::from(*byte)) << offset; + } + Ok((result, end_bytes)) + } else { + Err(DecodeError::TooShort) + } + } + } + }; +} + +macro_rules! impl_decodable_for_u8_array { + ($len: expr) => { + impl Decodable for [u8; $len] { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + if index + $len > bytes.len() { + Err(DecodeError::TooShort) + } else { + let mut array: [u8; $len] = [0; $len]; + array.copy_from_slice(&bytes[index..index + $len]); + + Ok((array, index + $len)) + } + } + } + }; +} + +impl_decodable_for_uint!(u16, 16); +impl_decodable_for_uint!(u32, 32); +impl_decodable_for_uint!(u64, 64); +impl_decodable_for_uint!(usize, 64); + +impl_decodable_for_u8_array!(4); + +impl Decodable for u8 { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + if index >= bytes.len() { + Err(DecodeError::TooShort) + } else { + Ok((bytes[index], index + 1)) + } + } +} + +impl Decodable for bool { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + if index >= bytes.len() { + Err(DecodeError::TooShort) + } else { + let result = match bytes[index] { + 0b0000_0000 => false, + 0b0000_0001 => true, + _ => return Err(DecodeError::Invalid), + }; + Ok((result, index + 1)) + } + } +} + +impl Decodable for H256 { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + if bytes.len() < 32 || bytes.len() - 32 < index { + Err(DecodeError::TooShort) + } else { + Ok((H256::from_slice(&bytes[index..(index + 32)]), index + 32)) + } + } +} + +impl Decodable for Address { + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + if bytes.len() < 20 || bytes.len() - 20 < index { + Err(DecodeError::TooShort) + } else { + Ok((Address::from_slice(&bytes[index..(index + 20)]), index + 20)) + } + } +} + +impl Decodable for Vec +where + T: Decodable, +{ + fn from_ssz_bytes(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { + decode_ssz_list(bytes, index) + } +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + + /* + #[test] + fn from_ssz_bytes_h256() { + /* + * Input is exact length + */ + let input = vec![42_u8; 32]; + let (decoded, i) = H256::from_ssz_bytes(&input).unwrap(); + assert_eq!(decoded.as_bytes(), &input[..]); + assert_eq!(i, 32); + + /* + * Input is too long + */ + let mut input = vec![42_u8; 32]; + input.push(12); + let (decoded, i) = H256::from_ssz_bytes(&input, 0).unwrap(); + assert_eq!(decoded.as_bytes(), &input[0..32]); + assert_eq!(i, 32); + + /* + * Input is too short + */ + let input = vec![42_u8; 31]; + let res = H256::from_ssz_bytes(&input, 0); + assert_eq!(res, Err(DecodeError::TooShort)); + } + */ + #[test] + fn from_ssz_bytes_vec_u16() { + assert_eq!(>::from_ssz_bytes(&[0, 0, 0, 0]), Ok(vec![0, 0])); + assert_eq!( + >::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]), + Ok(vec![0, 1, 2, 3]) + ); + /* + assert_eq!(::from_ssz_bytes(&[16, 0]), Ok(16)); + assert_eq!(::from_ssz_bytes(&[0, 1]), Ok(256)); + assert_eq!(::from_ssz_bytes(&[255, 255]), Ok(65535)); + + assert_eq!( + ::from_ssz_bytes(&[255]), + Err(DecodeError::InvalidByteLength { + given: 1, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + given: 0, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[0, 1, 2]), + Err(DecodeError::InvalidByteLength { + given: 3, + expected: 2 + }) + ); + */ + } + + #[test] + fn from_ssz_bytes_u16() { + assert_eq!(::from_ssz_bytes(&[0, 0]), Ok(0)); + assert_eq!(::from_ssz_bytes(&[16, 0]), Ok(16)); + assert_eq!(::from_ssz_bytes(&[0, 1]), Ok(256)); + assert_eq!(::from_ssz_bytes(&[255, 255]), Ok(65535)); + + assert_eq!( + ::from_ssz_bytes(&[255]), + Err(DecodeError::InvalidByteLength { + len: 1, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[]), + Err(DecodeError::InvalidByteLength { + len: 0, + expected: 2 + }) + ); + + assert_eq!( + ::from_ssz_bytes(&[0, 1, 2]), + Err(DecodeError::InvalidByteLength { + len: 3, + expected: 2 + }) + ); + } + + /* + #[test] + fn from_ssz_bytes_u32() { + let ssz = vec![0, 0, 0, 0]; + let (result, index): (u32, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(result, 0); + assert_eq!(index, 4); + + let ssz = vec![0, 1, 0, 0]; + let (result, index): (u32, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 4); + assert_eq!(result, 256); + + let ssz = vec![255, 255, 255, 0, 1, 0, 0]; + let (result, index): (u32, usize) = <_>::from_ssz_bytes(&ssz, 3).unwrap(); + assert_eq!(index, 7); + assert_eq!(result, 256); + + let ssz = vec![0, 1, 200, 0]; + let (result, index): (u32, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 4); + assert_eq!(result, 13107456); + + let ssz = vec![255, 255, 255, 255]; + let (result, index): (u32, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 4); + assert_eq!(result, 4294967295); + + let ssz = vec![1, 0, 0]; + let result: Result<(u32, usize), DecodeError> = <_>::from_ssz_bytes(&ssz); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + fn from_ssz_bytes_u64() { + let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; + let (result, index): (u64, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 8); + assert_eq!(result, 0); + + let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; + let (result, index): (u64, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 8); + assert_eq!(result, 18446744073709551615); + + let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255]; + let (result, index): (u64, usize) = <_>::from_ssz_bytes(&ssz, 3).unwrap(); + assert_eq!(index, 11); + assert_eq!(result, 18374686479671623680); + + let ssz = vec![0, 0, 0, 0, 0, 0, 0]; + let result: Result<(u64, usize), DecodeError> = <_>::from_ssz_bytes(&ssz); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + fn from_ssz_bytes_usize() { + let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; + let (result, index): (usize, usize) = <_>::from_ssz_bytes(&ssz).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, index): (usize, usize) = <_>::from_ssz_bytes(&ssz, 3).unwrap(); + assert_eq!(index, 11); + assert_eq!(result, 18446744073709551615); + + let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; + let (result, index): (usize, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 8); + assert_eq!(result, 18446744073709551615); + + let ssz = vec![0, 0, 0, 0, 0, 0, 1]; + let result: Result<(usize, usize), DecodeError> = <_>::from_ssz_bytes(&ssz); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + fn decode_ssz_bounds() { + let err: Result<(u16, usize), DecodeError> = <_>::from_ssz_bytes(&vec![1], 2); + assert_eq!(err, Err(DecodeError::TooShort)); + + let err: Result<(u16, usize), DecodeError> = <_>::from_ssz_bytes(&vec![0, 0, 0, 0], 3); + assert_eq!(err, Err(DecodeError::TooShort)); + + let result: u16 = <_>::from_ssz_bytes(&vec![0, 0, 0, 1, 0], 3).unwrap().0; + assert_eq!(result, 1); + } + + #[test] + fn decode_ssz_bool() { + let ssz = vec![0b0000_0000, 0b0000_0001]; + let (result, index): (bool, usize) = <_>::from_ssz_bytes(&ssz).unwrap(); + assert_eq!(index, 1); + assert_eq!(result, false); + + let (result, index): (bool, usize) = <_>::from_ssz_bytes(&ssz, 1).unwrap(); + assert_eq!(index, 2); + assert_eq!(result, true); + + let ssz = vec![0b0100_0000]; + let result: Result<(bool, usize), DecodeError> = <_>::from_ssz_bytes(&ssz); + assert_eq!(result, Err(DecodeError::Invalid)); + + let ssz = vec![]; + let result: Result<(bool, usize), DecodeError> = <_>::from_ssz_bytes(&ssz); + assert_eq!(result, Err(DecodeError::TooShort)); + } + + #[test] + #[should_panic] + fn decode_ssz_list_underflow() { + // SSZ encoded (u16::[1, 1, 1], u16::2) + let mut encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2, 0]; + let (decoded_array, i): (Vec, usize) = <_>::from_ssz_bytes(&encoded, 0).unwrap(); + let (decoded_u16, i): (u16, usize) = <_>::from_ssz_bytes(&encoded, i).unwrap(); + assert_eq!(decoded_array, vec![1, 1, 1]); + assert_eq!(decoded_u16, 2); + assert_eq!(i, 12); + + // Underflow + encoded[0] = 4; // change length to 4 from 6 + let (decoded_array, i): (Vec, usize) = <_>::from_ssz_bytes(&encoded, 0).unwrap(); + let (decoded_u16, _): (u16, usize) = <_>::from_ssz_bytes(&encoded, i).unwrap(); + assert_eq!(decoded_array, vec![1, 1]); + assert_eq!(decoded_u16, 2); + } + + #[test] + fn decode_too_long() { + let encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2]; + let decoded_array: Result, DecodeError> = decode(&encoded); + assert_eq!(decoded_array, Err(DecodeError::TooLong)); + } + + #[test] + fn decode_u8_array() { + let ssz = vec![0, 1, 2, 3]; + let result: [u8; 4] = decode(&ssz).unwrap(); + assert_eq!(result.len(), 4); + assert_eq!(result, [0, 1, 2, 3]); + } + */ +} diff --git a/eth2/utils/ssz2/src/encode/impls.rs b/eth2/utils/ssz2/src/encode/impls.rs index 88f343f5c0..0ffd07afb6 100644 --- a/eth2/utils/ssz2/src/encode/impls.rs +++ b/eth2/utils/ssz2/src/encode/impls.rs @@ -1,4 +1,4 @@ -use super::{Encodable, SszStream}; +use super::*; use ethereum_types::H256; macro_rules! impl_encodable_for_uint { @@ -31,13 +31,30 @@ impl Encodable for Vec { } fn as_ssz_bytes(&self) -> Vec { - let mut stream = SszStream::new(); + if T::is_ssz_fixed_len() { + let mut bytes = Vec::with_capacity(T::ssz_fixed_len() * self.len()); - for item in self { - stream.append(item) + for item in self { + bytes.append(&mut item.as_ssz_bytes()); + } + + bytes + } else { + let mut offset = self.len() * BYTES_PER_LENGTH_OFFSET; + let mut fixed = Vec::with_capacity(offset); + let mut variable = vec![]; + + for item in self { + fixed.append(&mut encode_length(offset)); + let mut bytes = item.as_ssz_bytes(); + offset += bytes.len(); + variable.append(&mut bytes); + } + + fixed.append(&mut variable); + + fixed } - - stream.drain() } } @@ -127,7 +144,7 @@ mod tests { use crate::ssz_encode; #[test] - fn test_vec_of_u8() { + fn vec_of_u8() { let vec: Vec = vec![]; assert_eq!(vec.as_ssz_bytes(), vec![]); @@ -139,19 +156,22 @@ mod tests { } #[test] - fn test_vec_of_vec_of_u8() { + fn vec_of_vec_of_u8() { let vec: Vec> = vec![vec![]]; - assert_eq!(vec.as_ssz_bytes(), vec![0, 0, 0, 0]); + assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]); + + let vec: Vec> = vec![vec![], vec![]]; + assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]); let vec: Vec> = vec![vec![0, 1, 2], vec![11, 22, 33]]; assert_eq!( vec.as_ssz_bytes(), - vec![3, 0, 0, 0, 3, 0, 0, 0, 0, 1, 2, 11, 22, 33] + vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33] ); } #[test] - fn test_ssz_encode_u8() { + fn ssz_encode_u8() { let x: u8 = 0; let mut ssz = SszStream::new(); ssz.append(&x); @@ -174,7 +194,7 @@ mod tests { } #[test] - fn test_ssz_encode_u16() { + fn ssz_encode_u16() { let x: u16 = 1; let mut ssz = SszStream::new(); ssz.append(&x); @@ -197,7 +217,7 @@ mod tests { } #[test] - fn test_ssz_encode_u32() { + fn ssz_encode_u32() { let x: u32 = 1; let mut ssz = SszStream::new(); ssz.append(&x); @@ -225,7 +245,7 @@ mod tests { } #[test] - fn test_ssz_encode_u64() { + fn ssz_encode_u64() { let x: u64 = 1; let mut ssz = SszStream::new(); ssz.append(&x); @@ -248,7 +268,7 @@ mod tests { } #[test] - fn test_ssz_encode_usize() { + fn ssz_encode_usize() { let x: usize = 1; let mut ssz = SszStream::new(); ssz.append(&x); @@ -272,7 +292,7 @@ mod tests { /* #[test] - fn test_ssz_encode_h256() { + fn ssz_encode_h256() { let h = H256::zero(); let mut ssz = SszStream::new(); ssz.append(&h); @@ -280,7 +300,7 @@ mod tests { } #[test] - fn test_ssz_mixed() { + fn ssz_mixed() { let mut stream = SszStream::new(); let h = H256::zero(); @@ -301,7 +321,7 @@ mod tests { } #[test] - fn test_ssz_encode_bool() { + fn ssz_encode_bool() { let x: bool = false; let mut ssz = SszStream::new(); ssz.append(&x); @@ -314,7 +334,7 @@ mod tests { } #[test] - fn test_ssz_encode_u8_array() { + fn ssz_encode_u8_array() { let x: [u8; 4] = [0, 1, 7, 8]; let ssz = ssz_encode(&x); assert_eq!(ssz, vec![0, 1, 7, 8]); diff --git a/eth2/utils/ssz2/src/impl_decode.rs b/eth2/utils/ssz2/src/impl_decode.rs deleted file mode 100644 index b4a00a12c5..0000000000 --- a/eth2/utils/ssz2/src/impl_decode.rs +++ /dev/null @@ -1,306 +0,0 @@ -use super::decode::decode_ssz_list; -use super::ethereum_types::{Address, H256}; -use super::{Decodable, DecodeError}; - -macro_rules! impl_decodable_for_uint { - ($type: ident, $bit_size: expr) => { - impl Decodable for $type { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - assert!((0 < $bit_size) & ($bit_size <= 64) & ($bit_size % 8 == 0)); - let max_bytes = $bit_size / 8; - if bytes.len() >= (index + max_bytes) { - let end_bytes = index + max_bytes; - let mut result: $type = 0; - for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) { - let offset = (i - index) * 8; - result |= ($type::from(*byte)) << offset; - } - Ok((result, end_bytes)) - } else { - Err(DecodeError::TooShort) - } - } - } - }; -} - -macro_rules! impl_decodable_for_u8_array { - ($len: expr) => { - impl Decodable for [u8; $len] { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index + $len > bytes.len() { - Err(DecodeError::TooShort) - } else { - let mut array: [u8; $len] = [0; $len]; - array.copy_from_slice(&bytes[index..index + $len]); - - Ok((array, index + $len)) - } - } - } - }; -} - -impl_decodable_for_uint!(u16, 16); -impl_decodable_for_uint!(u32, 32); -impl_decodable_for_uint!(u64, 64); -impl_decodable_for_uint!(usize, 64); - -impl_decodable_for_u8_array!(4); - -impl Decodable for u8 { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index >= bytes.len() { - Err(DecodeError::TooShort) - } else { - Ok((bytes[index], index + 1)) - } - } -} - -impl Decodable for bool { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if index >= bytes.len() { - Err(DecodeError::TooShort) - } else { - let result = match bytes[index] { - 0b0000_0000 => false, - 0b0000_0001 => true, - _ => return Err(DecodeError::Invalid), - }; - Ok((result, index + 1)) - } - } -} - -impl Decodable for H256 { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() < 32 || bytes.len() - 32 < index { - Err(DecodeError::TooShort) - } else { - Ok((H256::from_slice(&bytes[index..(index + 32)]), index + 32)) - } - } -} - -impl Decodable for Address { - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - if bytes.len() < 20 || bytes.len() - 20 < index { - Err(DecodeError::TooShort) - } else { - Ok((Address::from_slice(&bytes[index..(index + 20)]), index + 20)) - } - } -} - -impl Decodable for Vec -where - T: Decodable, -{ - fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), DecodeError> { - decode_ssz_list(bytes, index) - } -} - -#[cfg(test)] -mod tests { - use super::super::{decode, DecodeError}; - use super::*; - - #[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.as_bytes(), &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.as_bytes(), &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]; - - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 0); - assert_eq!(index, 2); - - let ssz = vec![16, 0]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 16); - assert_eq!(index, 2); - - let ssz = vec![0, 1]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 256); - assert_eq!(index, 2); - - let ssz = vec![255, 255]; - let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 2); - assert_eq!(result, 65535); - - let ssz = vec![1]; - let result: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_u32() { - let ssz = vec![0, 0, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(result, 0); - assert_eq!(index, 4); - - let ssz = vec![0, 1, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 256); - - let ssz = vec![255, 255, 255, 0, 1, 0, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 7); - assert_eq!(result, 256); - - let ssz = vec![0, 1, 200, 0]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 13107456); - - let ssz = vec![255, 255, 255, 255]; - let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 4); - assert_eq!(result, 4294967295); - - let ssz = vec![1, 0, 0]; - let result: Result<(u32, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_u64() { - let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 0); - - let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255]; - let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 11); - assert_eq!(result, 18374686479671623680); - - let ssz = vec![0, 0, 0, 0, 0, 0, 0]; - let result: Result<(u64, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_ssz_decode_usize() { - let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; - let (result, index): (usize, usize) = <_>::ssz_decode(&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, index): (usize, usize) = <_>::ssz_decode(&ssz, 3).unwrap(); - assert_eq!(index, 11); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; - let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 8); - assert_eq!(result, 18446744073709551615); - - let ssz = vec![0, 0, 0, 0, 0, 0, 1]; - let result: Result<(usize, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - fn test_decode_ssz_bounds() { - let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![1], 2); - assert_eq!(err, Err(DecodeError::TooShort)); - - let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![0, 0, 0, 0], 3); - assert_eq!(err, Err(DecodeError::TooShort)); - - let result: u16 = <_>::ssz_decode(&vec![0, 0, 0, 1, 0], 3).unwrap().0; - assert_eq!(result, 1); - } - - #[test] - fn test_decode_ssz_bool() { - let ssz = vec![0b0000_0000, 0b0000_0001]; - let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 0).unwrap(); - assert_eq!(index, 1); - assert_eq!(result, false); - - let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 1).unwrap(); - assert_eq!(index, 2); - assert_eq!(result, true); - - let ssz = vec![0b0100_0000]; - let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::Invalid)); - - let ssz = vec![]; - let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0); - assert_eq!(result, Err(DecodeError::TooShort)); - } - - #[test] - #[should_panic] - fn test_decode_ssz_list_underflow() { - // SSZ encoded (u16::[1, 1, 1], u16::2) - let mut encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2, 0]; - let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); - let (decoded_u16, i): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); - assert_eq!(decoded_array, vec![1, 1, 1]); - assert_eq!(decoded_u16, 2); - assert_eq!(i, 12); - - // Underflow - encoded[0] = 4; // change length to 4 from 6 - let (decoded_array, i): (Vec, usize) = <_>::ssz_decode(&encoded, 0).unwrap(); - let (decoded_u16, _): (u16, usize) = <_>::ssz_decode(&encoded, i).unwrap(); - assert_eq!(decoded_array, vec![1, 1]); - assert_eq!(decoded_u16, 2); - } - - #[test] - fn test_decode_too_long() { - let encoded = vec![6, 0, 0, 0, 1, 0, 1, 0, 1, 0, 2]; - let decoded_array: Result, DecodeError> = decode(&encoded); - assert_eq!(decoded_array, Err(DecodeError::TooLong)); - } - - #[test] - fn test_decode_u8_array() { - let ssz = vec![0, 1, 2, 3]; - let result: [u8; 4] = decode(&ssz).unwrap(); - assert_eq!(result.len(), 4); - assert_eq!(result, [0, 1, 2, 3]); - } -} diff --git a/eth2/utils/ssz2/src/lib.rs b/eth2/utils/ssz2/src/lib.rs index 49e6f31aff..572f42de0f 100644 --- a/eth2/utils/ssz2/src/lib.rs +++ b/eth2/utils/ssz2/src/lib.rs @@ -13,8 +13,10 @@ extern crate ethereum_types; pub mod decode; */ +mod decode; mod encode; +pub use decode::{Decodable, DecodeError}; pub use encode::{Encodable, SszStream}; pub const BYTES_PER_LENGTH_OFFSET: usize = 4; diff --git a/eth2/utils/ssz2/tests/tests.rs b/eth2/utils/ssz2/tests/tests.rs new file mode 100644 index 0000000000..3cf139b36c --- /dev/null +++ b/eth2/utils/ssz2/tests/tests.rs @@ -0,0 +1,22 @@ +use ssz2::{Decodable, Encodable}; + +fn round_trip(item: T) { + let encoded = &item.as_ssz_bytes(); + dbg!(encoded); + assert_eq!(T::from_ssz_bytes(&encoded), Ok(item)); +} + +#[test] +fn vec_u16_round_trip() { + round_trip::>(vec![]); + round_trip::>(vec![255]); + round_trip::>(vec![0, 1, 2]); + round_trip::>(vec![100; 64]); +} + +#[test] +fn vec_of_vec_u16_round_trip() { + // round_trip::>>(vec![]); + round_trip::>>(vec![vec![]]); + // round_trip::>>(vec![vec![], vec![]]); +}