Replace ssz with ssz2, adapt ssz_derive

This commit is contained in:
Paul Hauner
2019-05-04 14:11:48 +10:00
parent 7096d56749
commit 0bd5119f19
43 changed files with 351 additions and 16288 deletions

View File

@@ -1,16 +1,181 @@
use super::LENGTH_BYTES;
use super::*;
mod impls;
#[derive(Debug, PartialEq)]
pub enum DecodeError {
TooShort,
TooLong,
Invalid,
/// The bytes supplied were too short to be decoded into the specified type.
InvalidByteLength { len: usize, expected: usize },
/// The given bytes were too short to be read as a length prefix.
InvalidLengthPrefix { len: usize, expected: usize },
/// A length offset pointed to a byte that was out-of-bounds (OOB).
///
/// A bytes may be OOB for the following reasons:
///
/// - It is `>= bytes.len()`.
/// - When decoding variable length items, the 1st offset points "backwards" into the fixed
/// length items (i.e., `length[0] < BYTES_PER_LENGTH_OFFSET`).
/// - When decoding variable-length items, the `n`'th offset was less than the `n-1`'th offset.
OutOfBoundsByte { i: usize },
/// The given bytes were invalid for some application-level reason.
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<Self, DecodeError>;
}
#[derive(Copy, Clone)]
pub struct Offset {
position: usize,
offset: usize,
}
pub struct SszDecoderBuilder<'a> {
bytes: &'a [u8],
items: Vec<&'a [u8]>,
offsets: Vec<Offset>,
items_index: usize,
}
impl<'a> SszDecoderBuilder<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self {
bytes,
items: vec![],
offsets: vec![],
items_index: 0,
}
}
pub fn register_type<T: Decodable>(&mut self) -> Result<(), DecodeError> {
if T::is_ssz_fixed_len() {
let start = self.items_index;
self.items_index += T::ssz_fixed_len();
let slice = self.bytes.get(start..self.items_index).ok_or_else(|| {
DecodeError::InvalidByteLength {
len: self.bytes.len(),
expected: self.items_index,
}
})?;
self.items.push(slice);
} else {
let offset = read_offset(&self.bytes[self.items_index..])?;
let previous_offset = self
.offsets
.last()
.and_then(|o| Some(o.offset))
.unwrap_or_else(|| BYTES_PER_LENGTH_OFFSET);
if previous_offset > offset {
return Err(DecodeError::OutOfBoundsByte { i: offset });
} else if offset >= self.bytes.len() {
return Err(DecodeError::OutOfBoundsByte { i: offset });
}
self.offsets.push(Offset {
position: self.items.len(),
offset,
});
self.items_index += BYTES_PER_LENGTH_OFFSET;
}
Ok(())
}
fn apply_offsets(&mut self) -> Result<(), DecodeError> {
if !self.offsets.is_empty() {
let mut insertions = 0;
let mut running_offset = self.offsets[0].offset;
for i in 1..=self.offsets.len() {
let (slice_option, position) = if i == self.offsets.len() {
(self.bytes.get(running_offset..), self.offsets.len())
} else {
let offset = self.offsets[i];
let start = running_offset;
running_offset = offset.offset;
(self.bytes.get(start..running_offset), offset.position)
};
let slice = slice_option
.ok_or_else(|| DecodeError::OutOfBoundsByte { i: running_offset })?;
self.items.insert(position + insertions, slice);
insertions += 1;
}
}
Ok(())
}
pub fn build(mut self) -> Result<SszDecoder<'a>, DecodeError> {
self.apply_offsets()?;
Ok(SszDecoder { items: self.items })
}
}
pub struct SszDecoder<'a> {
items: Vec<&'a [u8]>,
}
impl<'a> SszDecoder<'a> {
/// Decodes the next item.
///
/// # Panics
///
/// Panics when attempting to decode more items than actually exist.
pub fn decode_next<T: Decodable>(&mut self) -> Result<T, DecodeError> {
T::from_ssz_bytes(self.items.remove(0))
}
}
/// Reads a `BYTES_PER_LENGTH_OFFSET`-byte length from `bytes`, where `bytes.len() >=
/// BYTES_PER_LENGTH_OFFSET`.
fn read_offset(bytes: &[u8]) -> Result<usize, DecodeError> {
decode_offset(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`.
fn decode_offset(bytes: &[u8]) -> Result<usize, DecodeError> {
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)
}
}
/*
/// Decode the given bytes for the given type
///
/// The single ssz encoded value/container/list will be decoded as the given type,
@@ -213,3 +378,4 @@ mod tests {
assert_eq!(decoded, Err(DecodeError::TooShort));
}
}
*/

View File

@@ -0,0 +1,547 @@
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<Self, DecodeError> {
let len = bytes.len();
let expected = <Self as Decodable>::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!(u8, 8);
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<T: Decodable> Decodable for Vec<T> {
fn is_ssz_fixed_len() -> bool {
false
}
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
if bytes.len() == 0 {
Ok(vec![])
} else if T::is_ssz_fixed_len() {
bytes
.chunks(T::ssz_fixed_len())
.map(|chunk| T::from_ssz_bytes(chunk))
.collect()
} else {
let mut next_variable_byte = read_offset(bytes)?;
// The value of the first offset must not point back into the same bytes that defined
// it.
if next_variable_byte < BYTES_PER_LENGTH_OFFSET {
return Err(DecodeError::OutOfBoundsByte {
i: next_variable_byte,
});
}
let num_items = next_variable_byte / BYTES_PER_LENGTH_OFFSET;
// The fixed-length section must be a clean multiple of `BYTES_PER_LENGTH_OFFSET`.
if next_variable_byte != num_items * BYTES_PER_LENGTH_OFFSET {
return Err(DecodeError::InvalidByteLength {
len: next_variable_byte,
expected: num_items * BYTES_PER_LENGTH_OFFSET,
});
}
let mut values = Vec::with_capacity(num_items);
for i in 1..=num_items {
let slice_option = if i == num_items {
bytes.get(next_variable_byte..)
} else {
let offset = read_offset(&bytes[(i * BYTES_PER_LENGTH_OFFSET)..])?;
let start = next_variable_byte;
next_variable_byte = offset;
// Note: the condition where `start > next_variable_byte` returns `None` which
// raises an error later in the program.
bytes.get(start..next_variable_byte)
};
let slice = slice_option.ok_or_else(|| DecodeError::OutOfBoundsByte {
i: next_variable_byte,
})?;
values.push(T::from_ssz_bytes(slice)?);
}
Ok(values)
}
}
}
/*
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<T> Decodable for Vec<T>
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 first_length_points_backwards() {
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[0, 0, 0, 0]),
Err(DecodeError::OutOfBoundsByte { i: 0 })
);
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[1, 0, 0, 0]),
Err(DecodeError::OutOfBoundsByte { i: 1 })
);
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[2, 0, 0, 0]),
Err(DecodeError::OutOfBoundsByte { i: 2 })
);
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[3, 0, 0, 0]),
Err(DecodeError::OutOfBoundsByte { i: 3 })
);
}
#[test]
fn lengths_are_decreasing() {
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[12, 0, 0, 0, 14, 0, 0, 0, 12, 0, 0, 0, 1, 0, 1, 0]),
Err(DecodeError::OutOfBoundsByte { i: 12 })
);
}
#[test]
fn awkward_fixed_lenth_portion() {
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[10, 0, 0, 0, 10, 0, 0, 0, 0, 0]),
Err(DecodeError::InvalidByteLength {
len: 10,
expected: 8
})
);
}
#[test]
fn length_out_of_bounds() {
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[5, 0, 0, 0]),
Err(DecodeError::InvalidByteLength {
len: 5,
expected: 4
})
);
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[8, 0, 0, 0, 9, 0, 0, 0]),
Err(DecodeError::OutOfBoundsByte { i: 9 })
);
}
#[test]
fn vec_of_vec_of_u16() {
assert_eq!(
<Vec<Vec<u16>>>::from_ssz_bytes(&[4, 0, 0, 0]),
Ok(vec![vec![]])
);
/*
assert_eq!(
<Vec<u16>>::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]),
Ok(vec![0, 1, 2, 3])
);
assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
assert_eq!(
<u16>::from_ssz_bytes(&[255]),
Err(DecodeError::InvalidByteLength {
len: 1,
expected: 2
})
);
assert_eq!(
<u16>::from_ssz_bytes(&[]),
Err(DecodeError::InvalidByteLength {
len: 0,
expected: 2
})
);
assert_eq!(
<u16>::from_ssz_bytes(&[0, 1, 2]),
Err(DecodeError::InvalidByteLength {
len: 3,
expected: 2
})
);
*/
}
#[test]
fn vec_of_u16() {
assert_eq!(<Vec<u16>>::from_ssz_bytes(&[0, 0, 0, 0]), Ok(vec![0, 0]));
assert_eq!(
<Vec<u16>>::from_ssz_bytes(&[0, 0, 1, 0, 2, 0, 3, 0]),
Ok(vec![0, 1, 2, 3])
);
assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
assert_eq!(
<u16>::from_ssz_bytes(&[255]),
Err(DecodeError::InvalidByteLength {
len: 1,
expected: 2
})
);
assert_eq!(
<u16>::from_ssz_bytes(&[]),
Err(DecodeError::InvalidByteLength {
len: 0,
expected: 2
})
);
assert_eq!(
<u16>::from_ssz_bytes(&[0, 1, 2]),
Err(DecodeError::InvalidByteLength {
len: 3,
expected: 2
})
);
}
#[test]
fn u16() {
assert_eq!(<u16>::from_ssz_bytes(&[0, 0]), Ok(0));
assert_eq!(<u16>::from_ssz_bytes(&[16, 0]), Ok(16));
assert_eq!(<u16>::from_ssz_bytes(&[0, 1]), Ok(256));
assert_eq!(<u16>::from_ssz_bytes(&[255, 255]), Ok(65535));
assert_eq!(
<u16>::from_ssz_bytes(&[255]),
Err(DecodeError::InvalidByteLength {
len: 1,
expected: 2
})
);
assert_eq!(
<u16>::from_ssz_bytes(&[]),
Err(DecodeError::InvalidByteLength {
len: 0,
expected: 2
})
);
assert_eq!(
<u16>::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<u16>, 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<u16>, 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<Vec<u16>, 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]);
}
*/
}

View File

@@ -1,87 +1,99 @@
use super::LENGTH_BYTES;
use super::*;
mod impls;
pub trait Encodable {
fn ssz_append(&self, s: &mut SszStream);
fn as_ssz_bytes(&self) -> Vec<u8>;
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
}
}
/// Provides a buffer for appending ssz-encodable values.
///
/// Use the `append()` fn to add a value to a list, then use
/// the `drain()` method to consume the struct and return the
/// ssz encoded bytes.
pub struct VariableLengths {
pub fixed_bytes_position: usize,
pub variable_bytes_length: usize,
}
/// Provides a buffer for appending SSZ values.
#[derive(Default)]
pub struct SszStream {
buffer: Vec<u8>,
fixed_bytes: Vec<u8>,
variable_bytes: Vec<u8>,
variable_lengths: Vec<VariableLengths>,
}
impl SszStream {
/// Create a new, empty stream for writing ssz values.
/// Create a new, empty stream for writing SSZ values.
pub fn new() -> Self {
SszStream { buffer: Vec::new() }
}
/// Append some ssz encodable value to the stream.
pub fn append<E>(&mut self, value: &E) -> &mut Self
where
E: Encodable,
{
value.ssz_append(self);
self
}
/// Append some ssz encoded bytes to the stream.
///
/// The length of the supplied bytes will be concatenated
/// to the stream before the supplied bytes.
pub fn append_encoded_val(&mut self, vec: &[u8]) {
self.buffer
.extend_from_slice(&encode_length(vec.len(), LENGTH_BYTES));
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: &[u8]) {
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
/// each item in the vector will be encoded and concatenated.
pub fn append_vec<E>(&mut self, vec: &[E])
where
E: Encodable,
{
let mut list_stream = SszStream::new();
for item in vec {
item.ssz_append(&mut list_stream);
SszStream {
fixed_bytes: vec![],
variable_bytes: vec![],
variable_lengths: vec![],
}
self.append_encoded_val(&list_stream.drain());
}
/// Consume the stream and return the underlying bytes.
pub fn drain(self) -> Vec<u8> {
self.buffer
/// Append some item to the stream.
pub fn append<T: Encodable>(&mut self, item: &T) {
let mut bytes = item.as_ssz_bytes();
if T::is_ssz_fixed_len() {
self.fixed_bytes.append(&mut bytes);
} else {
self.variable_lengths.push(VariableLengths {
fixed_bytes_position: self.fixed_bytes.len(),
variable_bytes_length: bytes.len(),
});
self.fixed_bytes
.append(&mut vec![0; BYTES_PER_LENGTH_OFFSET]);
self.variable_bytes.append(&mut bytes);
}
}
/// Update the offsets (if any) in the fixed-length bytes to correctly point to the values in
/// the variable length part.
pub fn apply_offsets(&mut self) {
let mut running_offset = self.fixed_bytes.len();
for v in &self.variable_lengths {
let offset = running_offset;
running_offset += v.variable_bytes_length;
self.fixed_bytes.splice(
v.fixed_bytes_position..v.fixed_bytes_position + BYTES_PER_LENGTH_OFFSET,
encode_length(offset),
);
}
}
/// Append the variable-length bytes to the fixed-length bytes and return the result.
pub fn drain(mut self) -> Vec<u8> {
self.apply_offsets();
self.fixed_bytes.append(&mut self.variable_bytes);
self.fixed_bytes
}
}
/// Encode some length into a ssz size prefix.
/// Encode `len` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length.
///
/// The ssz size prefix is 4 bytes, which is treated as a continuious
/// 32bit little-endian integer.
pub fn encode_length(len: usize, length_bytes: usize) -> Vec<u8> {
assert!(length_bytes > 0); // For sanity
assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8));
let mut header: Vec<u8> = vec![0; length_bytes];
for (i, header_byte) in header.iter_mut().enumerate() {
let offset = i * 8;
*header_byte = ((len >> offset) & 0xff) as u8;
}
header
/// If `len` is larger than `2 ^ BYTES_PER_LENGTH_OFFSET`, a `debug_assert` is raised.
pub fn encode_length(len: usize) -> Vec<u8> {
debug_assert!(len <= MAX_LENGTH_VALUE);
len.to_le_bytes()[0..BYTES_PER_LENGTH_OFFSET].to_vec()
}
/*
#[cfg(test)]
mod tests {
use super::*;
@@ -168,3 +180,4 @@ mod tests {
assert_eq!(ssz[7..9], *vec![200, 0]);
}
}
*/

View File

@@ -0,0 +1,272 @@
use super::*;
use ethereum_types::H256;
macro_rules! impl_encodable_for_uint {
($type: ident, $bit_size: expr) => {
impl Encodable for $type {
fn is_ssz_fixed_len() -> bool {
true
}
fn ssz_fixed_len() -> usize {
$bit_size / 8
}
fn as_ssz_bytes(&self) -> Vec<u8> {
self.to_le_bytes().to_vec()
}
}
};
}
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<T: Encodable> Encodable for Vec<T> {
fn is_ssz_fixed_len() -> bool {
false
}
fn as_ssz_bytes(&self) -> Vec<u8> {
if T::is_ssz_fixed_len() {
let mut bytes = Vec::with_capacity(T::ssz_fixed_len() * self.len());
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
}
}
}
/*
impl Encodable for bool {
fn ssz_fixed_len() -> Option<usize> {
Some(8)
}
fn as_ssz_bytes(&self) -> Vec<u8> {
(*self as u8).to_le_bytes().to_vec()
}
}
impl Encodable for H256 {
fn ssz_fixed_len() -> Option<usize> {
Some(32)
}
fn as_ssz_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
macro_rules! impl_encodable_for_u8_array {
($len: expr) => {
impl Encodable for [u8; $len] {
fn ssz_fixed_len() -> Option<usize> {
Some($len)
}
fn as_ssz_bytes(&self) -> Vec<u8> {
self.to_vec()
}
}
};
}
impl_encodable_for_u8_array!(4);
macro_rules! impl_encodable_for_u8_array {
($len: expr) => {
impl Encodable for [u8; $len] {
fn ssz_append(&self, s: &mut SszStream) {
let bytes: Vec<u8> = self.iter().cloned().collect();
s.append_encoded_raw(&bytes);
}
}
};
}
impl_encodable_for_u8_array!(4);
impl Encodable for bool {
fn ssz_append(&self, s: &mut SszStream) {
let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
s.append_encoded_raw(&[byte]);
}
}
impl Encodable for H256 {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl Encodable for Address {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl<T> Encodable for Vec<T>
where
T: Encodable,
{
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self);
}
}
*/
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vec_of_u8() {
let vec: Vec<u8> = vec![];
assert_eq!(vec.as_ssz_bytes(), vec![]);
let vec: Vec<u8> = vec![1];
assert_eq!(vec.as_ssz_bytes(), vec![1]);
let vec: Vec<u8> = vec![0, 1, 2, 3];
assert_eq!(vec.as_ssz_bytes(), vec![0, 1, 2, 3]);
}
#[test]
fn vec_of_vec_of_u8() {
let vec: Vec<Vec<u8>> = vec![];
assert_eq!(vec.as_ssz_bytes(), vec![]);
let vec: Vec<Vec<u8>> = vec![vec![]];
assert_eq!(vec.as_ssz_bytes(), vec![4, 0, 0, 0]);
let vec: Vec<Vec<u8>> = vec![vec![], vec![]];
assert_eq!(vec.as_ssz_bytes(), vec![8, 0, 0, 0, 8, 0, 0, 0]);
let vec: Vec<Vec<u8>> = vec![vec![0, 1, 2], vec![11, 22, 33]];
assert_eq!(
vec.as_ssz_bytes(),
vec![8, 0, 0, 0, 11, 0, 0, 0, 0, 1, 2, 11, 22, 33]
);
}
#[test]
fn ssz_encode_u8() {
assert_eq!(0_u8.as_ssz_bytes(), vec![0]);
assert_eq!(1_u8.as_ssz_bytes(), vec![1]);
assert_eq!(100_u8.as_ssz_bytes(), vec![100]);
assert_eq!(255_u8.as_ssz_bytes(), vec![255]);
}
#[test]
fn ssz_encode_u16() {
assert_eq!(1_u16.as_ssz_bytes(), vec![1, 0]);
assert_eq!(100_u16.as_ssz_bytes(), vec![100, 0]);
assert_eq!((1_u16 << 8).as_ssz_bytes(), vec![0, 1]);
assert_eq!(65535_u16.as_ssz_bytes(), vec![255, 255]);
}
#[test]
fn ssz_encode_u32() {
assert_eq!(1_u32.as_ssz_bytes(), vec![1, 0, 0, 0]);
assert_eq!(100_u32.as_ssz_bytes(), vec![100, 0, 0, 0]);
assert_eq!((1_u32 << 16).as_ssz_bytes(), vec![0, 0, 1, 0]);
assert_eq!((1_u32 << 24).as_ssz_bytes(), vec![0, 0, 0, 1]);
assert_eq!((!0_u32).as_ssz_bytes(), vec![255, 255, 255, 255]);
}
#[test]
fn ssz_encode_u64() {
assert_eq!(1_u64.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(
(!0_u64).as_ssz_bytes(),
vec![255, 255, 255, 255, 255, 255, 255, 255]
);
}
#[test]
fn ssz_encode_usize() {
assert_eq!(1_usize.as_ssz_bytes(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(
(!0_usize).as_ssz_bytes(),
vec![255, 255, 255, 255, 255, 255, 255, 255]
);
}
/*
#[test]
fn ssz_encode_h256() {
let h = H256::zero();
let mut ssz = SszStream::new();
ssz.append(&h);
assert_eq!(ssz.drain(), vec![0; 32]);
}
#[test]
fn ssz_mixed() {
let mut stream = SszStream::new();
let h = H256::zero();
let a: u8 = 100;
let b: u16 = 65535;
let c: u32 = 1 << 24;
stream.append(&h);
stream.append(&a);
stream.append(&b);
stream.append(&c);
let ssz = stream.drain();
assert_eq!(ssz[0..32], *vec![0; 32]);
assert_eq!(ssz[32], 100);
assert_eq!(ssz[33..55], *vec![255, 255]);
assert_eq!(ssz[55..59], *vec![0, 0, 0, 1]);
}
#[test]
fn ssz_encode_bool() {
let x: bool = false;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b0000_0000]);
let x: bool = true;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b0000_0001]);
}
#[test]
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]);
let x: [u8; 4] = [255, 255, 255, 255];
let ssz = ssz_encode(&x);
assert_eq!(ssz, vec![255, 255, 255, 255]);
}
*/
}

View File

@@ -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<T> Decodable for Vec<T>
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<u16>, 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<u16>, 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<Vec<u16>, 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]);
}
}

View File

@@ -1,275 +0,0 @@
extern crate bytes;
use self::bytes::{BufMut, BytesMut};
use super::ethereum_types::{Address, H256};
use super::{Encodable, SszStream};
/*
* Note: there is a "to_bytes" function for integers
* in Rust nightly. When it is in stable, we should
* use it instead.
*/
macro_rules! impl_encodable_for_uint {
($type: ident, $bit_size: expr) => {
impl Encodable for $type {
#[allow(clippy::cast_lossless)]
fn ssz_append(&self, s: &mut SszStream) {
// 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_le(*self as u16),
32 => buf.put_u32_le(*self as u32),
64 => buf.put_u64_le(*self as u64),
_ => {}
}
// Append bytes to the SszStream
s.append_encoded_raw(&buf.to_vec());
}
}
};
}
macro_rules! impl_encodable_for_u8_array {
($len: expr) => {
impl Encodable for [u8; $len] {
fn ssz_append(&self, s: &mut SszStream) {
let bytes: Vec<u8> = self.iter().cloned().collect();
s.append_encoded_raw(&bytes);
}
}
};
}
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_u8_array!(4);
impl Encodable for bool {
fn ssz_append(&self, s: &mut SszStream) {
let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
s.append_encoded_raw(&[byte]);
}
}
impl Encodable for H256 {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl Encodable for Address {
fn ssz_append(&self, s: &mut SszStream) {
s.append_encoded_raw(self.as_bytes());
}
}
impl<T> Encodable for Vec<T>
where
T: Encodable,
{
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ssz_encode;
#[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_address() {
let h = Address::zero();
let mut ssz = SszStream::new();
ssz.append(&h);
assert_eq!(ssz.drain(), vec![0; 20]);
}
#[test]
fn test_ssz_encode_u8() {
let x: u8 = 0;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0]);
let x: u8 = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![1]);
let x: u8 = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![100]);
let x: u8 = 255;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![255]);
}
#[test]
fn test_ssz_encode_u16() {
let x: u16 = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0]);
let x: u16 = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![100, 0]);
let x: u16 = 1 << 8;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 1]);
let x: u16 = 65535;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![255, 255]);
}
#[test]
fn test_ssz_encode_u32() {
let x: u32 = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0, 0, 0]);
let x: u32 = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![100, 0, 0, 0]);
let x: u32 = 1 << 16;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 1, 0]);
let x: u32 = 1 << 24;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 1]);
let x: u32 = !0;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![255, 255, 255, 255]);
}
#[test]
fn test_ssz_encode_u64() {
let x: u64 = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
let x: u64 = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);
let x: u64 = 1 << 32;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);
let x: u64 = !0;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]);
}
#[test]
fn test_ssz_encode_usize() {
let x: usize = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
let x: usize = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);
let x: usize = 1 << 32;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);
let x: usize = !0;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]);
}
#[test]
fn test_ssz_mixed() {
let mut stream = SszStream::new();
let h = Address::zero();
let a: u8 = 100;
let b: u16 = 65535;
let c: u32 = 1 << 24;
stream.append(&h);
stream.append(&a);
stream.append(&b);
stream.append(&c);
let ssz = stream.drain();
assert_eq!(ssz[0..20], *vec![0; 20]);
assert_eq!(ssz[20], 100);
assert_eq!(ssz[21..23], *vec![255, 255]);
assert_eq!(ssz[23..27], *vec![0, 0, 0, 1]);
}
#[test]
fn test_ssz_encode_bool() {
let x: bool = false;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b0000_0000]);
let x: bool = true;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b0000_0001]);
}
#[test]
fn test_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]);
let x: [u8; 4] = [255, 255, 255, 255];
let ssz = ssz_encode(&x);
assert_eq!(ssz, vec![255, 255, 255, 255]);
}
}

View File

@@ -7,11 +7,32 @@
* This implementation is not final and would almost certainly
* have issues.
*/
/*
extern crate bytes;
extern crate ethereum_types;
pub mod decode;
pub mod encode;
*/
mod decode;
mod encode;
pub use decode::{Decodable, DecodeError, SszDecoderBuilder};
pub use encode::{Encodable, SszStream};
pub const BYTES_PER_LENGTH_OFFSET: usize = 4;
pub const MAX_LENGTH_VALUE: usize = 1 << (BYTES_PER_LENGTH_OFFSET * 8) - 1;
/// Convenience function to SSZ encode an object supporting ssz::Encode.
pub fn ssz_encode<T>(val: &T) -> Vec<u8>
where
T: Encodable,
{
let mut ssz_stream = SszStream::new();
ssz_stream.append(val);
ssz_stream.drain()
}
/*
mod impl_decode;
mod impl_encode;
@@ -24,15 +45,6 @@ pub use hashing::hash;
pub const LENGTH_BYTES: usize = 4;
pub const MAX_LIST_SIZE: usize = 1 << (4 * 8);
/// Convenience function to SSZ encode an object supporting ssz::Encode.
pub fn ssz_encode<T>(val: &T) -> Vec<u8>
where
T: Encodable,
{
let mut ssz_stream = SszStream::new();
ssz_stream.append(val);
ssz_stream.drain()
}
#[cfg(test)]
mod tests {
@@ -223,3 +235,4 @@ mod tests {
}
}
}
*/