Merge ssz little endian branch

This commit is contained in:
Kirk Baird 2019-03-26 15:44:01 +11:00
commit 864ef137ef
No known key found for this signature in database
GPG Key ID: BF864B7ED0BEA33F
45 changed files with 14240 additions and 266 deletions

View File

@ -1,6 +1,6 @@
use super::BLOCKS_DB_COLUMN as DB_COLUMN; use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError}; use super::{ClientDB, DBError};
use ssz::Decodable; use ssz::decode;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, Hash256, Slot}; use types::{BeaconBlock, Hash256, Slot};
@ -30,7 +30,7 @@ impl<T: ClientDB> BeaconBlockStore<T> {
match self.get(&hash)? { match self.get(&hash)? {
None => Ok(None), None => Ok(None),
Some(ssz) => { Some(ssz) => {
let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError { let block = decode::<BeaconBlock>(&ssz).map_err(|_| DBError {
message: "Bad BeaconBlock SSZ.".to_string(), message: "Bad BeaconBlock SSZ.".to_string(),
})?; })?;
Ok(Some(block)) Ok(Some(block))

View File

@ -1,6 +1,6 @@
use super::STATES_DB_COLUMN as DB_COLUMN; use super::STATES_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError}; use super::{ClientDB, DBError};
use ssz::Decodable; use ssz::decode;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconState, Hash256}; use types::{BeaconState, Hash256};
@ -23,7 +23,7 @@ impl<T: ClientDB> BeaconStateStore<T> {
match self.get(&hash)? { match self.get(&hash)? {
None => Ok(None), None => Ok(None),
Some(ssz) => { Some(ssz) => {
let (state, _) = BeaconState::ssz_decode(&ssz, 0).map_err(|_| DBError { let state = decode::<BeaconState>(&ssz).map_err(|_| DBError {
message: "Bad State SSZ.".to_string(), message: "Bad State SSZ.".to_string(),
})?; })?;
Ok(Some(state)) Ok(Some(state))

View File

@ -4,7 +4,7 @@ use self::bytes::{BufMut, BytesMut};
use super::VALIDATOR_DB_COLUMN as DB_COLUMN; use super::VALIDATOR_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError}; use super::{ClientDB, DBError};
use bls::PublicKey; use bls::PublicKey;
use ssz::{ssz_encode, Decodable}; use ssz::{decode, ssz_encode};
use std::sync::Arc; use std::sync::Arc;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -69,8 +69,8 @@ impl<T: ClientDB> ValidatorStore<T> {
let val = self.db.get(DB_COLUMN, &key[..])?; let val = self.db.get(DB_COLUMN, &key[..])?;
match val { match val {
None => Ok(None), None => Ok(None),
Some(val) => match PublicKey::ssz_decode(&val, 0) { Some(val) => match decode::<PublicKey>(&val) {
Ok((key, _)) => Ok(Some(key)), Ok(key) => Ok(Some(key)),
Err(_) => Err(ValidatorStoreError::DecodeError), Err(_) => Err(ValidatorStoreError::DecodeError),
}, },
} }

View File

@ -6,7 +6,7 @@ use protos::services::{
}; };
use protos::services_grpc::ValidatorService; use protos::services_grpc::ValidatorService;
use slog::{debug, Logger}; use slog::{debug, Logger};
use ssz::Decodable; use ssz::decode;
#[derive(Clone)] #[derive(Clone)]
pub struct ValidatorServiceInstance { pub struct ValidatorServiceInstance {
@ -20,7 +20,7 @@ impl ValidatorService for ValidatorServiceInstance {
req: PublicKeyRequest, req: PublicKeyRequest,
sink: UnarySink<IndexResponse>, sink: UnarySink<IndexResponse>,
) { ) {
if let Ok((public_key, _)) = PublicKey::ssz_decode(req.get_public_key(), 0) { if let Ok(public_key) = decode::<PublicKey>(req.get_public_key()) {
debug!(self.log, "RPC request"; "endpoint" => "ValidatorIndex", "public_key" => public_key.concatenated_hex_id()); debug!(self.log, "RPC request"; "endpoint" => "ValidatorIndex", "public_key" => public_key.concatenated_hex_id());
let mut resp = IndexResponse::new(); let mut resp = IndexResponse::new();

View File

@ -130,4 +130,15 @@ mod epoch_tests {
assert_eq!(Slot::from(i), slots[i as usize]) assert_eq!(Slot::from(i), slots[i as usize])
} }
} }
#[test]
fn max_epoch_ssz() {
let max_epoch = Epoch::max_value();
let mut ssz = SszStream::new();
ssz.append(&max_epoch);
let encoded = ssz.drain();
assert_eq!(&encoded, &[255, 255, 255, 255, 255, 255, 255, 255]);
let (decoded, _i): (Epoch, usize) = <_>::ssz_decode(&encoded, 0).unwrap();
assert_eq!(max_epoch, decoded);
}
} }

View File

@ -5,13 +5,13 @@ macro_rules! ssz_tests {
#[test] #[test]
pub fn test_ssz_round_trip() { pub fn test_ssz_round_trip() {
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
use ssz::{ssz_encode, Decodable}; use ssz::{decode, ssz_encode};
let mut rng = XorShiftRng::from_seed([42; 16]); let mut rng = XorShiftRng::from_seed([42; 16]);
let original = $type::random_for_test(&mut rng); let original = $type::random_for_test(&mut rng);
let bytes = ssz_encode(&original); let bytes = ssz_encode(&original);
let (decoded, _) = $type::ssz_decode(&bytes, 0).unwrap(); let decoded: $type = decode(&bytes).unwrap();
assert_eq!(original, decoded); assert_eq!(original, decoded);
} }

View File

@ -173,7 +173,7 @@ impl TreeHash for AggregateSignature {
mod tests { mod tests {
use super::super::{Keypair, Signature}; use super::super::{Keypair, Signature};
use super::*; use super::*;
use ssz::ssz_encode; use ssz::{decode, ssz_encode};
#[test] #[test]
pub fn test_ssz_round_trip() { pub fn test_ssz_round_trip() {
@ -183,7 +183,7 @@ mod tests {
original.add(&Signature::new(&[42, 42], 0, &keypair.sk)); original.add(&Signature::new(&[42, 42], 0, &keypair.sk));
let bytes = ssz_encode(&original); let bytes = ssz_encode(&original);
let (decoded, _) = AggregateSignature::ssz_decode(&bytes, 0).unwrap(); let decoded = decode::<AggregateSignature>(&bytes).unwrap();
assert_eq!(original, decoded); assert_eq!(original, decoded);
} }

View File

@ -6,7 +6,6 @@ mod aggregate_signature;
mod keypair; mod keypair;
mod public_key; mod public_key;
mod secret_key; mod secret_key;
mod serde_vistors;
mod signature; mod signature;
pub use crate::aggregate_public_key::AggregatePublicKey; pub use crate::aggregate_public_key::AggregatePublicKey;

View File

@ -4,7 +4,8 @@ use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; use serde_hex::{encode as hex_encode, PrefixedHexVisitor};
use ssz::{ use ssz::{
decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream,
TreeHash,
}; };
use std::default; use std::default;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -90,9 +91,9 @@ impl<'de> Deserialize<'de> for PublicKey {
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?;
let obj = PublicKey::from_bytes(&bytes[..]) let pubkey = PublicKey::from_bytes(&bytes[..])
.map_err(|e| serde::de::Error::custom(format!("invalid pubkey ({:?})", e)))?; .map_err(|e| serde::de::Error::custom(format!("invalid pubkey ({:?})", e)))?;
Ok(obj) Ok(pubkey)
} }
} }

View File

@ -1,9 +1,11 @@
use super::serde_vistors::HexVisitor;
use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey}; use bls_aggregates::{DecodeError as BlsDecodeError, SecretKey as RawSecretKey};
use hex::encode as hex_encode; use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use ssz::{decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use serde_hex::HexVisitor;
use ssz::{
decode, decode_ssz_list, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash,
};
/// A single BLS signature. /// A single BLS signature.
/// ///
@ -59,9 +61,9 @@ impl<'de> Deserialize<'de> for SecretKey {
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let bytes = deserializer.deserialize_str(HexVisitor)?; let bytes = deserializer.deserialize_str(HexVisitor)?;
let (pubkey, _) = <_>::ssz_decode(&bytes[..], 0) let secret_key = decode::<SecretKey>(&bytes[..])
.map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?;
Ok(pubkey) Ok(secret_key)
} }
} }

View File

@ -1,21 +0,0 @@
use hex;
use serde::de::{self, Visitor};
use std::fmt;
pub struct HexVisitor;
impl<'de> Visitor<'de> for HexVisitor {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a hex string (irrelevant of prefix)")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(hex::decode(value.trim_start_matches("0x"))
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))?)
}
}

View File

@ -1,11 +1,12 @@
use super::serde_vistors::HexVisitor;
use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE}; use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE};
use bls_aggregates::Signature as RawSignature; use bls_aggregates::Signature as RawSignature;
use hex::encode as hex_encode; use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use serde_hex::HexVisitor;
use ssz::{ use ssz::{
decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash, decode, decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream,
TreeHash,
}; };
/// A single BLS signature. /// A single BLS signature.
@ -136,7 +137,7 @@ impl<'de> Deserialize<'de> for Signature {
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let bytes: Vec<u8> = deserializer.deserialize_str(HexVisitor)?; let bytes = deserializer.deserialize_str(HexVisitor)?;
let signature = Signature::from_bytes(&bytes[..]) let signature = Signature::from_bytes(&bytes[..])
.map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?; .map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?;
Ok(signature) Ok(signature)
@ -156,7 +157,7 @@ mod tests {
let original = Signature::new(&[42, 42], 0, &keypair.sk); let original = Signature::new(&[42, 42], 0, &keypair.sk);
let bytes = ssz_encode(&original); let bytes = ssz_encode(&original);
let (decoded, _) = Signature::ssz_decode(&bytes, 0).unwrap(); let decoded = decode::<Signature>(&bytes).unwrap();
assert_eq!(original, decoded); assert_eq!(original, decoded);
} }

View File

@ -6,7 +6,7 @@ use bit_vec::BitVec;
use serde::de::{Deserialize, Deserializer}; use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer}; use serde::ser::{Serialize, Serializer};
use serde_hex::{encode, PrefixedHexVisitor}; use serde_hex::{encode, PrefixedHexVisitor};
use ssz::Decodable; use ssz::{Decodable, Encodable};
use std::cmp; use std::cmp;
use std::default; use std::default;
@ -144,14 +144,14 @@ impl std::ops::BitAnd for BooleanBitfield {
} }
} }
impl ssz::Encodable for BooleanBitfield { impl Encodable for BooleanBitfield {
// ssz_append encodes Self according to the `ssz` spec. // ssz_append encodes Self according to the `ssz` spec.
fn ssz_append(&self, s: &mut ssz::SszStream) { fn ssz_append(&self, s: &mut ssz::SszStream) {
s.append_vec(&self.to_bytes()) s.append_vec(&self.to_bytes())
} }
} }
impl ssz::Decodable for BooleanBitfield { impl Decodable for BooleanBitfield {
fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), ssz::DecodeError> { fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), ssz::DecodeError> {
let len = ssz::decode::decode_length(bytes, index, ssz::LENGTH_BYTES)?; let len = ssz::decode::decode_length(bytes, index, ssz::LENGTH_BYTES)?;
if (ssz::LENGTH_BYTES + len) > bytes.len() { if (ssz::LENGTH_BYTES + len) > bytes.len() {
@ -210,7 +210,7 @@ impl ssz::TreeHash for BooleanBitfield {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use ssz::{ssz_encode, Decodable, SszStream}; use ssz::{decode, ssz_encode, SszStream};
#[test] #[test]
fn test_new_bitfield() { fn test_new_bitfield() {
@ -378,12 +378,12 @@ mod tests {
let mut stream = SszStream::new(); let mut stream = SszStream::new();
stream.append(&field); stream.append(&field);
assert_eq!(stream.drain(), vec![0, 0, 0, 2, 225, 192]); assert_eq!(stream.drain(), vec![2, 0, 0, 0, 225, 192]);
let field = BooleanBitfield::from_elem(18, true); let field = BooleanBitfield::from_elem(18, true);
let mut stream = SszStream::new(); let mut stream = SszStream::new();
stream.append(&field); stream.append(&field);
assert_eq!(stream.drain(), vec![0, 0, 0, 3, 255, 255, 192]); assert_eq!(stream.drain(), vec![3, 0, 0, 0, 255, 255, 192]);
} }
fn create_test_bitfield() -> BooleanBitfield { fn create_test_bitfield() -> BooleanBitfield {
@ -399,13 +399,13 @@ mod tests {
#[test] #[test]
fn test_ssz_decode() { fn test_ssz_decode() {
let encoded = vec![0, 0, 0, 2, 225, 192]; let encoded = vec![2, 0, 0, 0, 225, 192];
let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); let field = decode::<BooleanBitfield>(&encoded).unwrap();
let expected = create_test_bitfield(); let expected = create_test_bitfield();
assert_eq!(field, expected); assert_eq!(field, expected);
let encoded = vec![0, 0, 0, 3, 255, 255, 3]; let encoded = vec![3, 0, 0, 0, 255, 255, 3];
let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap(); let field = decode::<BooleanBitfield>(&encoded).unwrap();
let expected = BooleanBitfield::from_bytes(&[255, 255, 3]); let expected = BooleanBitfield::from_bytes(&[255, 255, 3]);
assert_eq!(field, expected); assert_eq!(field, expected);
} }
@ -414,7 +414,7 @@ mod tests {
fn test_ssz_round_trip() { fn test_ssz_round_trip() {
let original = BooleanBitfield::from_bytes(&vec![18; 12][..]); let original = BooleanBitfield::from_bytes(&vec![18; 12][..]);
let ssz = ssz_encode(&original); let ssz = ssz_encode(&original);
let (decoded, _) = BooleanBitfield::ssz_decode(&ssz, 0).unwrap(); let decoded = decode::<BooleanBitfield>(&ssz).unwrap();
assert_eq!(original, decoded); assert_eq!(original, decoded);
} }

View File

@ -38,6 +38,24 @@ impl<'de> Visitor<'de> for PrefixedHexVisitor {
} }
} }
pub struct HexVisitor;
impl<'de> Visitor<'de> for HexVisitor {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a hex string (irrelevant of prefix)")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(hex::decode(value.trim_start_matches("0x"))
.map_err(|e| de::Error::custom(format!("invalid hex ({:?})", e)))?)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -8,3 +8,5 @@ edition = "2018"
bytes = "0.4.9" bytes = "0.4.9"
ethereum-types = "0.5" ethereum-types = "0.5"
hashing = { path = "../hashing" } hashing = { path = "../hashing" }
hex = "0.3"
yaml-rust = "0.4"

View File

@ -69,7 +69,7 @@ Syntax:
| Shorthand | Meaning | | Shorthand | Meaning |
|:-------------|:----------------------------------------------------| |:-------------|:----------------------------------------------------|
| `big` | ``big endian`` | | `little` | ``little endian`` |
| `to_bytes` | convert to bytes. Params: ``(size, byte order)`` | | `to_bytes` | convert to bytes. Params: ``(size, byte order)`` |
| `from_bytes` | convert from bytes. Params: ``(bytes, byte order)`` | | `from_bytes` | convert from bytes. Params: ``(bytes, byte order)`` |
| `value` | the value to serialize | | `value` | the value to serialize |
@ -82,7 +82,7 @@ Syntax:
Convert directly to bytes the size of the int. (e.g. ``int16 = 2 bytes``) Convert directly to bytes the size of the int. (e.g. ``int16 = 2 bytes``)
All integers are serialized as **big endian**. All integers are serialized as **little endian**.
| Check to perform | Code | | Check to perform | Code |
|:-----------------------|:------------------------| |:-----------------------|:------------------------|
@ -92,7 +92,7 @@ All integers are serialized as **big endian**.
```python ```python
buffer_size = int_size / 8 buffer_size = int_size / 8
return value.to_bytes(buffer_size, 'big') return value.to_bytes(buffer_size, 'little')
``` ```
#### Address #### Address
@ -131,7 +131,7 @@ For general `byte` type:
value_bytes ]`` value_bytes ]``
```python ```python
byte_length = (len(value)).to_bytes(4, 'big') byte_length = (len(value)).to_bytes(4, 'little')
return byte_length + value return byte_length + value
``` ```
@ -175,12 +175,12 @@ At each step, the following checks should be made:
Convert directly from bytes into integer utilising the number of bytes the same Convert directly from bytes into integer utilising the number of bytes the same
size as the integer length. (e.g. ``int16 == 2 bytes``) size as the integer length. (e.g. ``int16 == 2 bytes``)
All integers are interpreted as **big endian**. All integers are interpreted as **little endian**.
```python ```python
byte_length = int_size / 8 byte_length = int_size / 8
new_index = current_index + int_size new_index = current_index + int_size
return int.from_bytes(rawbytes[current_index:current_index+int_size], 'big'), new_index return int.from_bytes(rawbytes[current_index:current_index+int_size], 'little'), new_index
``` ```
#### Address #### Address
@ -206,7 +206,7 @@ return rawbytes[current_index:current_index+32], new_index
Get the length of the bytes, return the bytes. Get the length of the bytes, return the bytes.
```python ```python
bytes_length = int.from_bytes(rawbytes[current_index:current_index+4], 'big') bytes_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little')
new_index = current_index + 4 + bytes_lenth new_index = current_index + 4 + bytes_lenth
return rawbytes[current_index+4:current_index+4+bytes_length], new_index return rawbytes[current_index+4:current_index+4+bytes_length], new_index
``` ```
@ -224,7 +224,7 @@ entire length of the list.
| rawbytes has enough left for length | ``len(rawbytes) > current_index + 4`` | | rawbytes has enough left for length | ``len(rawbytes) > current_index + 4`` |
```python ```python
total_length = int.from_bytes(rawbytes[current_index:current_index+4], 'big') total_length = int.from_bytes(rawbytes[current_index:current_index+4], 'little')
new_index = current_index + 4 + total_length new_index = current_index + 4 + total_length
item_index = current_index + 4 item_index = current_index + 4
deserialized_list = [] deserialized_list = []

View File

@ -9,7 +9,7 @@ publish = false
cargo-fuzz = true cargo-fuzz = true
[dependencies] [dependencies]
ethereum-types = "0.4.0" ethereum-types = "0.5"
[dependencies.ssz] [dependencies.ssz]
path = ".." path = ".."
@ -84,22 +84,22 @@ path = "fuzz_targets/fuzz_target_address_decode.rs"
name = "fuzz_target_address_encode" name = "fuzz_target_address_encode"
path = "fuzz_targets/fuzz_target_address_encode.rs" path = "fuzz_targets/fuzz_target_address_encode.rs"
[[bin]]
name = "fuzz_target_vec_decode"
path = "fuzz_targets/fuzz_target_vec_decode.rs"
[[bin]] [[bin]]
name = "fuzz_target_vec_address_decode" name = "fuzz_target_vec_address_decode"
path = "fuzz_targets/fuzz_target_vec_address_decode.rs" path = "fuzz_targets/fuzz_target_vec_address_decode.rs"
[[bin]]
name = "fuzz_target_vec_u64_decode"
path = "fuzz_targets/fuzz_target_vec_u64_decode.rs"
[[bin]] [[bin]]
name = "fuzz_target_vec_bool_decode" name = "fuzz_target_vec_bool_decode"
path = "fuzz_targets/fuzz_target_vec_bool_decode.rs" path = "fuzz_targets/fuzz_target_vec_bool_decode.rs"
[[bin]]
name = "fuzz_target_vec_decode"
path = "fuzz_targets/fuzz_target_vec_decode.rs"
[[bin]] [[bin]]
name = "fuzz_target_vec_encode" name = "fuzz_target_vec_encode"
path = "fuzz_targets/fuzz_target_vec_encode.rs" path = "fuzz_targets/fuzz_target_vec_encode.rs"
[[bin]]
name = "fuzz_target_vec_u64_decode"
path = "fuzz_targets/fuzz_target_vec_u64_decode.rs"

View File

@ -4,18 +4,17 @@ extern crate ethereum_types;
extern crate ssz; extern crate ssz;
use ethereum_types::Address; use ethereum_types::Address;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(Address, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<Address, DecodeError> = decode(data);
if data.len() >= 20 { if data.len() == 20 {
// Should have valid result // Should have valid result
let (address, index) = result.unwrap(); let address = result.unwrap();
assert_eq!(index, 20);
assert_eq!(address, Address::from_slice(&data[..20])); assert_eq!(address, Address::from_slice(&data[..20]));
} else { } else {
// Length of less than 32 should return error // Length of less than 32 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -2,27 +2,23 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(bool, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<bool, DecodeError> = decode(data);
if data.len() >= 1 { if data.len() == 1 {
// TODO: change to little endian bytes if data[0] == 1 {
// https://github.com/sigp/lighthouse/issues/215 let val_bool = result.unwrap();
if data[0] == u8::pow(2,7) {
let (val_bool, index) = result.unwrap();
assert!(val_bool); assert!(val_bool);
assert_eq!(index, 1);
} else if data[0] == 0 { } else if data[0] == 0 {
let (val_bool, index) = result.unwrap(); let val_bool = result.unwrap();
assert!(!val_bool); assert!(!val_bool);
assert_eq!(index, 1);
} else { } else {
assert_eq!(result, Err(DecodeError::Invalid)); assert_eq!(result, Err(DecodeError::Invalid));
} }
} else { } else {
// Length of 0 should return error // Length of 0 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -15,8 +15,6 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&val_bool); ssz.append(&val_bool);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes assert_eq!(val_bool, ssz[0]);
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(val_bool, ssz[0] % u8::pow(2, 6));
assert_eq!(ssz.len(), 1); assert_eq!(ssz.len(), 1);
}); });

View File

@ -4,18 +4,17 @@ extern crate ethereum_types;
extern crate ssz; extern crate ssz;
use ethereum_types::H256; use ethereum_types::H256;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(H256, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<H256, DecodeError> = decode(data);
if data.len() >= 32 { if data.len() == 32 {
// Should have valid result // Should have valid result
let (hash, index) = result.unwrap(); let hash = result.unwrap();
assert_eq!(index, 32);
assert_eq!(hash, H256::from_slice(&data[..32])); assert_eq!(hash, H256::from_slice(&data[..32]));
} else { } else {
// Length of less than 32 should return error // Length of less than 32 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -2,21 +2,18 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(u16, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<u16, DecodeError> = decode(data);
if data.len() >= 2 { if data.len() == 2 {
// Valid result // Valid result
let (number_u16, index) = result.unwrap(); let number_u16 = result.unwrap();
assert_eq!(index, 2); let val = u16::from_le_bytes([data[0], data[1]]);
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
let val = u16::from_be_bytes([data[0], data[1]]);
assert_eq!(number_u16, val); assert_eq!(number_u16, val);
} else { } else {
// Length of 0 or 1 should return error // Length of 0 or 1 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -15,8 +15,6 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_u16); ssz.append(&number_u16);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(ssz.len(), 2); assert_eq!(ssz.len(), 2);
assert_eq!(number_u16, u16::from_be_bytes([ssz[0], ssz[1]])); assert_eq!(number_u16, u16::from_le_bytes([ssz[0], ssz[1]]));
}); });

View File

@ -2,21 +2,18 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(u32, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<u32, DecodeError> = decode(data);
if data.len() >= 4 { if data.len() == 4 {
// Valid result // Valid result
let (number_u32, index) = result.unwrap(); let number_u32 = result.unwrap();
assert_eq!(index, 4); let val = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
let val = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
assert_eq!(number_u32, val); assert_eq!(number_u32, val);
} else { } else {
// Length less then 4 should return error // Length not 4 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -15,8 +15,6 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_u32); ssz.append(&number_u32);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(ssz.len(), 4); assert_eq!(ssz.len(), 4);
assert_eq!(number_u32, u32::from_be_bytes([ssz[0], ssz[1], ssz[2], ssz[3]])); assert_eq!(number_u32, u32::from_le_bytes([ssz[0], ssz[1], ssz[2], ssz[3]]));
}); });

View File

@ -2,18 +2,15 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(u64, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<u64, DecodeError> = decode(data);
if data.len() >= 8 { if data.len() == 8 {
// Valid result // Valid result
let (number_u64, index) = result.unwrap(); let number_u64 = result.unwrap();
assert_eq!(index, 8); let val = u64::from_le_bytes([
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
let val = u64::from_be_bytes([
data[0], data[0],
data[1], data[1],
data[2], data[2],
@ -25,7 +22,7 @@ fuzz_target!(|data: &[u8]| {
]); ]);
assert_eq!(number_u64, val); assert_eq!(number_u64, val);
} else { } else {
// Length less then 8 should return error // Length not 8 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -9,7 +9,7 @@ fuzz_target!(|data: &[u8]| {
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
let mut number_u64 = 0; let mut number_u64 = 0;
if data.len() >= 8 { if data.len() >= 8 {
number_u64 = u64::from_be_bytes([ number_u64 = u64::from_le_bytes([
data[0], data[0],
data[1], data[1],
data[2], data[2],
@ -24,10 +24,8 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_u64); ssz.append(&number_u64);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(ssz.len(), 8); assert_eq!(ssz.len(), 8);
assert_eq!(number_u64, u64::from_be_bytes([ assert_eq!(number_u64, u64::from_le_bytes([
ssz[0], ssz[0],
ssz[1], ssz[1],
ssz[2], ssz[2],

View File

@ -2,20 +2,17 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let result: Result<(u8, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<u8, DecodeError> = decode(data);
if data.len() >= 1 { if data.len() == 1 {
// Should have valid result // Should have valid result
let (number_u8, index) = result.unwrap(); let number_u8 = result.unwrap();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(index, 1);
assert_eq!(number_u8, data[0]); assert_eq!(number_u8, data[0]);
} else { } else {
// Length of 0 should return error // Length not 1 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -15,8 +15,6 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_u8); ssz.append(&number_u8);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(number_u8, ssz[0]); assert_eq!(number_u8, ssz[0]);
assert_eq!(ssz.len(), 1); assert_eq!(ssz.len(), 1);
}); });

View File

@ -2,19 +2,16 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{DecodeError, decode};
// Fuzz ssz_decode() // Fuzz decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
// Note: we assume architecture is 64 bit -> usize == 64 bits // Note: we assume architecture is 64 bit -> usize == 64 bits
let result: Result<(usize, usize), DecodeError> = Decodable::ssz_decode(data, 0); let result: Result<usize, DecodeError> = decode(data);
if data.len() >= 8 { if data.len() == 8 {
// Valid result // Valid result
let (number_usize, index) = result.unwrap(); let number_usize = result.unwrap();
assert_eq!(index, 8); let val = u64::from_le_bytes([
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
let val = u64::from_be_bytes([
data[0], data[0],
data[1], data[1],
data[2], data[2],
@ -27,6 +24,6 @@ fuzz_target!(|data: &[u8]| {
assert_eq!(number_usize, val as usize); assert_eq!(number_usize, val as usize);
} else { } else {
// Length less then 8 should return error // Length less then 8 should return error
assert_eq!(result, Err(DecodeError::TooShort)); assert!(result.is_err());
} }
}); });

View File

@ -9,7 +9,7 @@ fuzz_target!(|data: &[u8]| {
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
let mut number_usize = 0; let mut number_usize = 0;
if data.len() >= 8 { if data.len() >= 8 {
number_usize = u64::from_be_bytes([ number_usize = u64::from_le_bytes([
data[0], data[0],
data[1], data[1],
data[2], data[2],
@ -24,10 +24,8 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_usize); ssz.append(&number_usize);
let ssz = ssz.drain(); let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(ssz.len(), 8); assert_eq!(ssz.len(), 8);
assert_eq!(number_usize, u64::from_be_bytes([ assert_eq!(number_usize, u64::from_le_bytes([
ssz[0], ssz[0],
ssz[1], ssz[1],
ssz[2], ssz[2],

View File

@ -4,9 +4,9 @@ extern crate ethereum_types;
extern crate ssz; extern crate ssz;
use ethereum_types::{Address}; use ethereum_types::{Address};
use ssz::{DecodeError, Decodable}; use ssz::{decode, DecodeError};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let _result: Result<(Vec<Address>, usize), DecodeError> = Decodable::ssz_decode(data, 0); let _result: Result<Vec<Address>, DecodeError> = decode(data);
}); });

View File

@ -2,9 +2,9 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{decode, DecodeError};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let _result: Result<(Vec<bool>, usize), DecodeError> = Decodable::ssz_decode(data, 0); let _result: Result<Vec<bool>, DecodeError> = decode(data);
}); });

View File

@ -3,10 +3,9 @@
extern crate ethereum_types; extern crate ethereum_types;
extern crate ssz; extern crate ssz;
use ethereum_types::{Address, H256}; use ssz::{decode, DecodeError, Decodable};
use ssz::{DecodeError, Decodable};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let _result: Result<(Vec<u8>, usize), DecodeError> = Decodable::ssz_decode(data, 0); let _result: Result<Vec<u8>, DecodeError> = decode(data);
}); });

View File

@ -3,7 +3,6 @@
extern crate ethereum_types; extern crate ethereum_types;
extern crate ssz; extern crate ssz;
use ethereum_types::{Address, H256};
use ssz::SszStream; use ssz::SszStream;
// Fuzz ssz_encode() // Fuzz ssz_encode()

View File

@ -2,9 +2,9 @@
#[macro_use] extern crate libfuzzer_sys; #[macro_use] extern crate libfuzzer_sys;
extern crate ssz; extern crate ssz;
use ssz::{DecodeError, Decodable}; use ssz::{decode, DecodeError};
// Fuzz ssz_decode() // Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let _result: Result<(Vec<u64>, usize), DecodeError> = Decodable::ssz_decode(data, 0); let _result: Result<Vec<u64>, DecodeError> = decode(data);
}); });

View File

@ -13,16 +13,22 @@ pub trait Decodable: Sized {
/// Decode the given bytes for the given type /// Decode the given bytes for the given type
/// ///
/// The single ssz encoded value will be decoded as the given type at the /// The single ssz encoded value/container/list will be decoded as the given type,
/// given index. /// by recursively calling `ssz_decode`.
pub fn decode_ssz<T>(ssz_bytes: &[u8], index: usize) -> Result<(T, usize), DecodeError> pub fn decode<T>(ssz_bytes: &[u8]) -> Result<(T), DecodeError>
where where
T: Decodable, T: Decodable,
{ {
if index >= ssz_bytes.len() { let (decoded, i): (T, usize) = match T::ssz_decode(ssz_bytes, 0) {
return Err(DecodeError::TooShort); Err(e) => return Err(e),
Ok(v) => v,
};
if i < ssz_bytes.len() {
return Err(DecodeError::TooLong);
} }
T::ssz_decode(ssz_bytes, index)
Ok(decoded)
} }
/// Decode a vector (list) of encoded bytes. /// Decode a vector (list) of encoded bytes.
@ -65,7 +71,7 @@ where
} }
/// Given some number of bytes, interpret the first four /// Given some number of bytes, interpret the first four
/// bytes as a 32-bit big-endian integer and return the /// bytes as a 32-bit little-endian integer and return the
/// result. /// result.
pub fn decode_length( pub fn decode_length(
bytes: &[u8], bytes: &[u8],
@ -82,7 +88,7 @@ pub fn decode_length(
.take(index + length_bytes) .take(index + length_bytes)
.skip(index) .skip(index)
{ {
let offset = (index + length_bytes - i - 1) * 8; let offset = (i - index) * 8;
len |= (*byte as usize) << offset; len |= (*byte as usize) << offset;
} }
Ok(len) Ok(len)
@ -90,18 +96,18 @@ pub fn decode_length(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::super::encode::encode_length; use super::super::encode::*;
use super::*; use super::*;
#[test] #[test]
fn test_ssz_decode_length() { fn test_ssz_decode_length() {
let decoded = decode_length(&vec![0, 0, 0, 1], 0, LENGTH_BYTES); let decoded = decode_length(&vec![1, 0, 0, 0], 0, LENGTH_BYTES);
assert_eq!(decoded.unwrap(), 1); assert_eq!(decoded.unwrap(), 1);
let decoded = decode_length(&vec![0, 0, 1, 0], 0, LENGTH_BYTES); let decoded = decode_length(&vec![0, 1, 0, 0], 0, LENGTH_BYTES);
assert_eq!(decoded.unwrap(), 256); assert_eq!(decoded.unwrap(), 256);
let decoded = decode_length(&vec![0, 0, 1, 255], 0, LENGTH_BYTES); let decoded = decode_length(&vec![255, 1, 0, 0], 0, LENGTH_BYTES);
assert_eq!(decoded.unwrap(), 511); assert_eq!(decoded.unwrap(), 511);
let decoded = decode_length(&vec![255, 255, 255, 255], 0, LENGTH_BYTES); let decoded = decode_length(&vec![255, 255, 255, 255], 0, LENGTH_BYTES);
@ -132,21 +138,35 @@ mod tests {
} }
} }
#[test]
fn test_encode_decode_ssz_list() {
let test_vec: Vec<u16> = vec![256; 12];
let mut stream = SszStream::new();
stream.append_vec(&test_vec);
let ssz = stream.drain();
// u16
let decoded: (Vec<u16>, usize) = decode_ssz_list(&ssz, 0).unwrap();
assert_eq!(decoded.0, test_vec);
assert_eq!(decoded.1, LENGTH_BYTES + (12 * 2));
}
#[test] #[test]
fn test_decode_ssz_list() { fn test_decode_ssz_list() {
// u16 // u16
let v: Vec<u16> = vec![10, 10, 10, 10]; let v: Vec<u16> = vec![10, 10, 10, 10];
let decoded: (Vec<u16>, usize) = let decoded: (Vec<u16>, usize) =
decode_ssz_list(&vec![0, 0, 0, 8, 0, 10, 0, 10, 0, 10, 0, 10], 0).unwrap(); decode_ssz_list(&vec![8, 0, 0, 0, 10, 0, 10, 0, 10, 0, 10, 0], 0).unwrap();
assert_eq!(decoded.0, v); assert_eq!(decoded.0, v);
assert_eq!(decoded.1, 12); assert_eq!(decoded.1, LENGTH_BYTES + (4 * 2));
// u32 // u32
let v: Vec<u32> = vec![10, 10, 10, 10]; let v: Vec<u32> = vec![10, 10, 10, 10];
let decoded: (Vec<u32>, usize) = decode_ssz_list( let decoded: (Vec<u32>, usize) = decode_ssz_list(
&vec![ &vec![
0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 00,
], ],
0, 0,
) )
@ -158,36 +178,37 @@ mod tests {
let v: Vec<u64> = vec![10, 10, 10, 10]; let v: Vec<u64> = vec![10, 10, 10, 10];
let decoded: (Vec<u64>, usize) = decode_ssz_list( let decoded: (Vec<u64>, usize) = decode_ssz_list(
&vec![ &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, 32, 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,
10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0,
], ],
0, 0,
) )
.unwrap(); .unwrap();
assert_eq!(decoded.0, v); assert_eq!(decoded.0, v);
assert_eq!(decoded.1, 36); assert_eq!(decoded.1, LENGTH_BYTES + (8 * 4));
// Check that it can accept index // Check that it can accept index
let v: Vec<usize> = vec![15, 15, 15, 15]; let v: Vec<usize> = vec![15, 15, 15, 15];
let offset = 10;
let decoded: (Vec<usize>, usize) = decode_ssz_list( let decoded: (Vec<usize>, usize) = decode_ssz_list(
&vec![ &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, 1, 2, 3, 4, 5, 6, 7, 8, 9, 32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 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, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0,
], ],
10, offset,
) )
.unwrap(); .unwrap();
assert_eq!(decoded.0, v); assert_eq!(decoded.0, v);
assert_eq!(decoded.1, 46); assert_eq!(decoded.1, offset + LENGTH_BYTES + (8 * 4));
// Check that length > bytes throws error // Check that length > bytes throws error
let decoded: Result<(Vec<usize>, usize), DecodeError> = let decoded: Result<(Vec<usize>, usize), DecodeError> =
decode_ssz_list(&vec![0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15], 0); decode_ssz_list(&vec![32, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0], 0);
assert_eq!(decoded, Err(DecodeError::TooShort)); assert_eq!(decoded, Err(DecodeError::TooShort));
// Check that incorrect index throws error // Check that incorrect index throws error
let decoded: Result<(Vec<usize>, usize), DecodeError> = let decoded: Result<(Vec<usize>, usize), DecodeError> =
decode_ssz_list(&vec![0, 0, 0, 0, 0, 0, 0, 15], 16); decode_ssz_list(&vec![15, 0, 0, 0, 0, 0, 0, 0], 16);
assert_eq!(decoded, Err(DecodeError::TooShort)); assert_eq!(decoded, Err(DecodeError::TooShort));
} }
} }

View File

@ -70,13 +70,13 @@ impl SszStream {
/// Encode some length into a ssz size prefix. /// Encode some length into a ssz size prefix.
/// ///
/// The ssz size prefix is 4 bytes, which is treated as a continuious /// The ssz size prefix is 4 bytes, which is treated as a continuious
/// 32bit big-endian integer. /// 32bit little-endian integer.
pub fn encode_length(len: usize, length_bytes: usize) -> Vec<u8> { pub fn encode_length(len: usize, length_bytes: usize) -> Vec<u8> {
assert!(length_bytes > 0); // For sanity assert!(length_bytes > 0); // For sanity
assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8)); assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8));
let mut header: Vec<u8> = vec![0; length_bytes]; let mut header: Vec<u8> = vec![0; length_bytes];
for (i, header_byte) in header.iter_mut().enumerate() { for (i, header_byte) in header.iter_mut().enumerate() {
let offset = (length_bytes - i - 1) * 8; let offset = i * 8;
*header_byte = ((len >> offset) & 0xff) as u8; *header_byte = ((len >> offset) & 0xff) as u8;
} }
header header
@ -95,15 +95,27 @@ mod tests {
#[test] #[test]
fn test_encode_length_4_bytes() { fn test_encode_length_4_bytes() {
assert_eq!(encode_length(0, LENGTH_BYTES), vec![0; 4]); assert_eq!(encode_length(0, LENGTH_BYTES), vec![0; 4]);
assert_eq!(encode_length(1, LENGTH_BYTES), vec![0, 0, 0, 1]); assert_eq!(encode_length(1, LENGTH_BYTES), vec![1, 0, 0, 0]);
assert_eq!(encode_length(255, LENGTH_BYTES), vec![0, 0, 0, 255]); assert_eq!(encode_length(255, LENGTH_BYTES), vec![255, 0, 0, 0]);
assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 0, 1, 0]); assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 1, 0, 0]);
assert_eq!( assert_eq!(
encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1 encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1
vec![255, 255, 255, 255] vec![255, 255, 255, 255]
); );
} }
#[test]
fn test_encode_lower_length() {
assert_eq!(encode_length(0, LENGTH_BYTES - 2), vec![0; 2]);
assert_eq!(encode_length(1, LENGTH_BYTES - 2), vec![1, 0]);
}
#[test]
fn test_encode_higher_length() {
assert_eq!(encode_length(0, LENGTH_BYTES + 2), vec![0; 6]);
assert_eq!(encode_length(1, LENGTH_BYTES + 2), vec![1, 0, 0, 0, 0, 0]);
}
#[test] #[test]
#[should_panic] #[should_panic]
fn test_encode_length_4_bytes_panic() { fn test_encode_length_4_bytes_panic() {
@ -117,8 +129,42 @@ mod tests {
stream.append_vec(&test_vec); stream.append_vec(&test_vec);
let ssz = stream.drain(); let ssz = stream.drain();
assert_eq!(ssz.len(), 4 + (12 * 2)); assert_eq!(ssz.len(), LENGTH_BYTES + (12 * 2));
assert_eq!(ssz[0..4], *vec![0, 0, 0, 24]); assert_eq!(ssz[0..4], *vec![24, 0, 0, 0]);
assert_eq!(ssz[4..6], *vec![1, 0]); assert_eq!(ssz[4..6], *vec![0, 1]);
}
#[test]
fn test_encode_mixed_prefixed() {
let test_vec: Vec<u16> = vec![100, 200];
let test_value: u8 = 5;
let mut stream = SszStream::new();
stream.append_vec(&test_vec);
stream.append(&test_value);
let ssz = stream.drain();
assert_eq!(ssz.len(), LENGTH_BYTES + (2 * 2) + 1);
assert_eq!(ssz[0..4], *vec![4, 0, 0, 0]);
assert_eq!(ssz[4..6], *vec![100, 0]);
assert_eq!(ssz[6..8], *vec![200, 0]);
assert_eq!(ssz[8], 5);
}
#[test]
fn test_encode_mixed_postfixed() {
let test_value: u8 = 5;
let test_vec: Vec<u16> = vec![100, 200];
let mut stream = SszStream::new();
stream.append(&test_value);
stream.append_vec(&test_vec);
let ssz = stream.drain();
assert_eq!(ssz.len(), 1 + LENGTH_BYTES + (2 * 2));
assert_eq!(ssz[0], 5);
assert_eq!(ssz[1..5], *vec![4, 0, 0, 0]);
assert_eq!(ssz[5..7], *vec![100, 0]);
assert_eq!(ssz[7..9], *vec![200, 0]);
} }
} }

View File

@ -12,7 +12,7 @@ macro_rules! impl_decodable_for_uint {
let end_bytes = index + max_bytes; let end_bytes = index + max_bytes;
let mut result: $type = 0; let mut result: $type = 0;
for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) { for (i, byte) in bytes.iter().enumerate().take(end_bytes).skip(index) {
let offset = (end_bytes - i - 1) * 8; let offset = (i - index) * 8;
result |= ($type::from(*byte)) << offset; result |= ($type::from(*byte)) << offset;
} }
Ok((result, end_bytes)) Ok((result, end_bytes))
@ -65,7 +65,7 @@ impl Decodable for bool {
} else { } else {
let result = match bytes[index] { let result = match bytes[index] {
0b0000_0000 => false, 0b0000_0000 => false,
0b1000_0000 => true, 0b0000_0001 => true,
_ => return Err(DecodeError::Invalid), _ => return Err(DecodeError::Invalid),
}; };
Ok((result, index + 1)) Ok((result, index + 1))
@ -104,7 +104,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::super::{decode_ssz, DecodeError}; use super::super::{decode, DecodeError};
use super::*; use super::*;
#[test] #[test]
@ -138,139 +138,169 @@ mod tests {
fn test_ssz_decode_u16() { fn test_ssz_decode_u16() {
let ssz = vec![0, 0]; let ssz = vec![0, 0];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(result, 0); assert_eq!(result, 0);
assert_eq!(index, 2); assert_eq!(index, 2);
let ssz = vec![0, 16]; let ssz = vec![16, 0];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(result, 16); assert_eq!(result, 16);
assert_eq!(index, 2); assert_eq!(index, 2);
let ssz = vec![1, 0]; let ssz = vec![0, 1];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(result, 256); assert_eq!(result, 256);
assert_eq!(index, 2); assert_eq!(index, 2);
let ssz = vec![255, 255]; let ssz = vec![255, 255];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u16, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 2); assert_eq!(index, 2);
assert_eq!(result, 65535); assert_eq!(result, 65535);
let ssz = vec![1]; let ssz = vec![1];
let result: Result<(u16, usize), DecodeError> = decode_ssz(&ssz, 0); let result: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&ssz, 0);
assert_eq!(result, Err(DecodeError::TooShort)); assert_eq!(result, Err(DecodeError::TooShort));
} }
#[test] #[test]
fn test_ssz_decode_u32() { fn test_ssz_decode_u32() {
let ssz = vec![0, 0, 0, 0]; let ssz = vec![0, 0, 0, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(result, 0); assert_eq!(result, 0);
assert_eq!(index, 4); assert_eq!(index, 4);
let ssz = vec![0, 0, 1, 0]; let ssz = vec![0, 1, 0, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 4); assert_eq!(index, 4);
assert_eq!(result, 256); assert_eq!(result, 256);
let ssz = vec![255, 255, 255, 0, 0, 1, 0]; let ssz = vec![255, 255, 255, 0, 1, 0, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 3).unwrap(); let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 3).unwrap();
assert_eq!(index, 7); assert_eq!(index, 7);
assert_eq!(result, 256); assert_eq!(result, 256);
let ssz = vec![0, 200, 1, 0]; let ssz = vec![0, 1, 200, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 4); assert_eq!(index, 4);
assert_eq!(result, 13107456); assert_eq!(result, 13107456);
let ssz = vec![255, 255, 255, 255]; let ssz = vec![255, 255, 255, 255];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 4); assert_eq!(index, 4);
assert_eq!(result, 4294967295); assert_eq!(result, 4294967295);
let ssz = vec![0, 0, 1]; let ssz = vec![1, 0, 0];
let result: Result<(u32, usize), DecodeError> = decode_ssz(&ssz, 0); let result: Result<(u32, usize), DecodeError> = <_>::ssz_decode(&ssz, 0);
assert_eq!(result, Err(DecodeError::TooShort)); assert_eq!(result, Err(DecodeError::TooShort));
} }
#[test] #[test]
fn test_ssz_decode_u64() { fn test_ssz_decode_u64() {
let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0];
let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 8); assert_eq!(index, 8);
assert_eq!(result, 0); assert_eq!(result, 0);
let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255]; let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255];
let (result, index): (u64, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 8); assert_eq!(index, 8);
assert_eq!(result, 18446744073709551615); assert_eq!(result, 18446744073709551615);
let ssz = vec![0, 0, 8, 255, 0, 0, 0, 0, 0, 0, 0]; let ssz = vec![0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 255];
let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap(); let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 3).unwrap();
assert_eq!(index, 11); assert_eq!(index, 11);
assert_eq!(result, 18374686479671623680); assert_eq!(result, 18374686479671623680);
let ssz = vec![0, 0, 0, 0, 0, 0, 0]; let ssz = vec![0, 0, 0, 0, 0, 0, 0];
let result: Result<(u64, usize), DecodeError> = decode_ssz(&ssz, 0); let result: Result<(u64, usize), DecodeError> = <_>::ssz_decode(&ssz, 0);
assert_eq!(result, Err(DecodeError::TooShort)); assert_eq!(result, Err(DecodeError::TooShort));
} }
#[test] #[test]
fn test_ssz_decode_usize() { fn test_ssz_decode_usize() {
let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0]; let ssz = vec![0, 0, 0, 0, 0, 0, 0, 0];
let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 8); assert_eq!(index, 8);
assert_eq!(result, 0); assert_eq!(result, 0);
let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255]; let ssz = vec![0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255];
let (result, index): (usize, usize) = decode_ssz(&ssz, 3).unwrap(); let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 3).unwrap();
assert_eq!(index, 11); assert_eq!(index, 11);
assert_eq!(result, 18446744073709551615); assert_eq!(result, 18446744073709551615);
let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255]; let ssz = vec![255, 255, 255, 255, 255, 255, 255, 255, 255];
let (result, index): (usize, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (usize, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 8); assert_eq!(index, 8);
assert_eq!(result, 18446744073709551615); assert_eq!(result, 18446744073709551615);
let ssz = vec![0, 0, 0, 0, 0, 0, 1]; let ssz = vec![0, 0, 0, 0, 0, 0, 1];
let result: Result<(usize, usize), DecodeError> = decode_ssz(&ssz, 0); let result: Result<(usize, usize), DecodeError> = <_>::ssz_decode(&ssz, 0);
assert_eq!(result, Err(DecodeError::TooShort)); assert_eq!(result, Err(DecodeError::TooShort));
} }
#[test] #[test]
fn test_decode_ssz_bounds() { fn test_decode_ssz_bounds() {
let err: Result<(u16, usize), DecodeError> = decode_ssz(&vec![1], 2); let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![1], 2);
assert_eq!(err, Err(DecodeError::TooShort)); assert_eq!(err, Err(DecodeError::TooShort));
let err: Result<(u16, usize), DecodeError> = decode_ssz(&vec![0, 0, 0, 0], 3); let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![0, 0, 0, 0], 3);
assert_eq!(err, Err(DecodeError::TooShort)); assert_eq!(err, Err(DecodeError::TooShort));
let result: u16 = decode_ssz(&vec![0, 0, 0, 0, 1], 3).unwrap().0; let result: u16 = <_>::ssz_decode(&vec![0, 0, 0, 1, 0], 3).unwrap().0;
assert_eq!(result, 1); assert_eq!(result, 1);
} }
#[test] #[test]
fn test_decode_ssz_bool() { fn test_decode_ssz_bool() {
let ssz = vec![0b0000_0000, 0b1000_0000]; let ssz = vec![0b0000_0000, 0b0000_0001];
let (result, index): (bool, usize) = decode_ssz(&ssz, 0).unwrap(); let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 1); assert_eq!(index, 1);
assert_eq!(result, false); assert_eq!(result, false);
let (result, index): (bool, usize) = decode_ssz(&ssz, 1).unwrap(); let (result, index): (bool, usize) = <_>::ssz_decode(&ssz, 1).unwrap();
assert_eq!(index, 2); assert_eq!(index, 2);
assert_eq!(result, true); assert_eq!(result, true);
let ssz = vec![0b0100_0000]; let ssz = vec![0b0100_0000];
let result: Result<(bool, usize), DecodeError> = decode_ssz(&ssz, 0); let result: Result<(bool, usize), DecodeError> = <_>::ssz_decode(&ssz, 0);
assert_eq!(result, Err(DecodeError::Invalid)); 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] #[test]
fn test_decode_u8_array() { fn test_decode_u8_array() {
let ssz = vec![0, 1, 2, 3]; let ssz = vec![0, 1, 2, 3];
let (result, index): ([u8; 4], usize) = decode_ssz(&ssz, 0).unwrap(); let result: [u8; 4] = decode(&ssz).unwrap();
assert_eq!(index, 4); assert_eq!(result.len(), 4);
assert_eq!(result, [0, 1, 2, 3]); assert_eq!(result, [0, 1, 2, 3]);
} }
} }

View File

@ -27,9 +27,9 @@ macro_rules! impl_encodable_for_uint {
// Match bit size with encoding // Match bit size with encoding
match $bit_size { match $bit_size {
8 => buf.put_u8(*self as u8), 8 => buf.put_u8(*self as u8),
16 => buf.put_u16_be(*self as u16), 16 => buf.put_u16_le(*self as u16),
32 => buf.put_u32_be(*self as u32), 32 => buf.put_u32_le(*self as u32),
64 => buf.put_u64_be(*self as u64), 64 => buf.put_u64_le(*self as u64),
_ => {} _ => {}
} }
@ -61,7 +61,7 @@ impl_encodable_for_u8_array!(4);
impl Encodable for bool { impl Encodable for bool {
fn ssz_append(&self, s: &mut SszStream) { fn ssz_append(&self, s: &mut SszStream) {
let byte = if *self { 0b1000_0000 } else { 0b0000_0000 }; let byte = if *self { 0b0000_0001 } else { 0b0000_0000 };
s.append_encoded_raw(&[byte]); s.append_encoded_raw(&[byte]);
} }
} }
@ -136,17 +136,17 @@ mod tests {
let x: u16 = 1; let x: u16 = 1;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 1]); assert_eq!(ssz.drain(), vec![1, 0]);
let x: u16 = 100; let x: u16 = 100;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 100]); assert_eq!(ssz.drain(), vec![100, 0]);
let x: u16 = 1 << 8; let x: u16 = 1 << 8;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0]); assert_eq!(ssz.drain(), vec![0, 1]);
let x: u16 = 65535; let x: u16 = 65535;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
@ -159,22 +159,22 @@ mod tests {
let x: u32 = 1; let x: u32 = 1;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 1]); assert_eq!(ssz.drain(), vec![1, 0, 0, 0]);
let x: u32 = 100; let x: u32 = 100;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 100]); assert_eq!(ssz.drain(), vec![100, 0, 0, 0]);
let x: u32 = 1 << 16; let x: u32 = 1 << 16;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 1, 0, 0]); assert_eq!(ssz.drain(), vec![0, 0, 1, 0]);
let x: u32 = 1 << 24; let x: u32 = 1 << 24;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![1, 0, 0, 0]); assert_eq!(ssz.drain(), vec![0, 0, 0, 1]);
let x: u32 = !0; let x: u32 = !0;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
@ -187,17 +187,17 @@ mod tests {
let x: u64 = 1; let x: u64 = 1;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
let x: u64 = 100; let x: u64 = 100;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);
let x: u64 = 1 << 32; let x: u64 = 1 << 32;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);
let x: u64 = !0; let x: u64 = !0;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
@ -210,17 +210,17 @@ mod tests {
let x: usize = 1; let x: usize = 1;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 1]); assert_eq!(ssz.drain(), vec![1, 0, 0, 0, 0, 0, 0, 0]);
let x: usize = 100; let x: usize = 100;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 0, 0, 0, 100]); assert_eq!(ssz.drain(), vec![100, 0, 0, 0, 0, 0, 0, 0]);
let x: usize = 1 << 32; let x: usize = 1 << 32;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 0, 0, 1, 0, 0, 0, 0]); assert_eq!(ssz.drain(), vec![0, 0, 0, 0, 1, 0, 0, 0]);
let x: usize = !0; let x: usize = !0;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
@ -228,6 +228,27 @@ mod tests {
assert_eq!(ssz.drain(), vec![255, 255, 255, 255, 255, 255, 255, 255]); 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] #[test]
fn test_ssz_encode_bool() { fn test_ssz_encode_bool() {
let x: bool = false; let x: bool = false;
@ -238,7 +259,7 @@ mod tests {
let x: bool = true; let x: bool = true;
let mut ssz = SszStream::new(); let mut ssz = SszStream::new();
ssz.append(&x); ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b1000_0000]); assert_eq!(ssz.drain(), vec![0b0000_0001]);
} }
#[test] #[test]

View File

@ -19,7 +19,7 @@ mod impl_decode;
mod impl_encode; mod impl_encode;
mod impl_tree_hash; mod impl_tree_hash;
pub use crate::decode::{decode_ssz, decode_ssz_list, Decodable, DecodeError}; pub use crate::decode::{decode, decode_ssz_list, Decodable, DecodeError};
pub use crate::encode::{Encodable, SszStream}; pub use crate::encode::{Encodable, SszStream};
pub use crate::signed_root::SignedRoot; pub use crate::signed_root::SignedRoot;
pub use crate::tree_hash::{merkle_hash, TreeHash}; pub use crate::tree_hash::{merkle_hash, TreeHash};
@ -38,3 +38,193 @@ where
ssz_stream.append(val); ssz_stream.append(val);
ssz_stream.drain() ssz_stream.drain()
} }
#[cfg(test)]
mod tests {
extern crate hex;
extern crate yaml_rust;
use self::yaml_rust::yaml;
use super::*;
use std::{fs::File, io::prelude::*, path::PathBuf};
#[test]
pub fn test_vector_uint_bounds() {
let mut file = {
let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
file_path_buf.push("src/test_vectors/uint_bounds.yaml");
File::open(file_path_buf).unwrap()
};
let mut yaml_str = String::new();
file.read_to_string(&mut yaml_str).unwrap();
let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
let doc = &docs[0];
// Load test cases
let test_cases = doc["test_cases"].clone();
for test_case in test_cases {
// Only the valid cases are checked as parse::<uX>() will fail for all invalid cases
if test_case["valid"].as_bool().unwrap() {
// Convert test vector 'ssz' encoded yaml to Vec<u8>
let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x");
let test_vector_bytes = hex::decode(ssz).unwrap();
// Convert test vector 'value' to ssz encoded bytes
let mut bytes: Vec<u8>;
match test_case["type"].as_str().unwrap() {
"uint8" => {
let value: u8 = test_case["value"].as_str().unwrap().parse::<u8>().unwrap();
bytes = ssz_encode::<u8>(&value); // check encoding
// Check decoding
let decoded = decode::<u8>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint16" => {
let value: u16 =
test_case["value"].as_str().unwrap().parse::<u16>().unwrap();
bytes = ssz_encode::<u16>(&value);
// Check decoding
let decoded = decode::<u16>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint32" => {
let value: u32 =
test_case["value"].as_str().unwrap().parse::<u32>().unwrap();
bytes = ssz_encode::<u32>(&value);
// Check decoding
let decoded = decode::<u32>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint64" => {
let value: u64 =
test_case["value"].as_str().unwrap().parse::<u64>().unwrap();
bytes = ssz_encode::<u64>(&value);
// Check decoding
let decoded = decode::<u64>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
_ => continue,
};
assert_eq!(test_vector_bytes, bytes);
}
}
}
#[test]
pub fn test_vector_uint_random() {
let mut file = {
let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
file_path_buf.push("src/test_vectors/uint_random.yaml");
File::open(file_path_buf).unwrap()
};
let mut yaml_str = String::new();
file.read_to_string(&mut yaml_str).unwrap();
let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
let doc = &docs[0];
// Load test cases
let test_cases = doc["test_cases"].clone();
for test_case in test_cases {
// Only the valid cases are checked as parse::<uX>() will fail for all invalid cases
if test_case["valid"].as_bool().unwrap() {
// Convert test vector 'ssz' encoded yaml to Vec<u8>
let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x");
let test_vector_bytes = hex::decode(ssz).unwrap();
// Convert test vector 'value' to ssz encoded bytes
let mut bytes: Vec<u8>;
match test_case["type"].as_str().unwrap() {
"uint8" => {
let value: u8 = test_case["value"].as_str().unwrap().parse::<u8>().unwrap();
bytes = ssz_encode::<u8>(&value); // check encoding
// Check decoding
let decoded = decode::<u8>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint16" => {
let value: u16 =
test_case["value"].as_str().unwrap().parse::<u16>().unwrap();
bytes = ssz_encode::<u16>(&value);
// Check decoding
let decoded = decode::<u16>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint32" => {
let value: u32 =
test_case["value"].as_str().unwrap().parse::<u32>().unwrap();
bytes = ssz_encode::<u32>(&value);
// Check decoding
let decoded = decode::<u32>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
"uint64" => {
let value: u64 =
test_case["value"].as_str().unwrap().parse::<u64>().unwrap();
bytes = ssz_encode::<u64>(&value);
// Check decoding
let decoded = decode::<u64>(&test_vector_bytes).unwrap();
assert_eq!(decoded, value);
}
_ => continue,
};
assert_eq!(test_vector_bytes, bytes);
}
}
}
#[test]
pub fn test_vector_uint_wrong_length() {
let mut file = {
let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
file_path_buf.push("src/test_vectors/uint_wrong_length.yaml");
File::open(file_path_buf).unwrap()
};
let mut yaml_str = String::new();
file.read_to_string(&mut yaml_str).unwrap();
let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
let doc = &docs[0];
// Load test cases
let test_cases = doc["test_cases"].clone();
for test_case in test_cases {
// Convert test vector 'ssz' encoded yaml to Vec<u8>
let ssz = test_case["ssz"].as_str().unwrap().trim_start_matches("0x");
let test_vector_bytes = hex::decode(ssz).unwrap();
// Attempt to decode invalid ssz bytes
match test_case["type"].as_str().unwrap() {
"uint8" => {
let decoded = decode::<u8>(&test_vector_bytes);
assert!(decoded.is_err());
}
"uint16" => {
let decoded = decode::<u16>(&test_vector_bytes);
assert!(decoded.is_err());
}
"uint32" => {
let decoded = decode::<u32>(&test_vector_bytes);
assert!(decoded.is_err());
}
"uint64" => {
let decoded = decode::<u64>(&test_vector_bytes);
assert!(decoded.is_err());
}
_ => continue,
};
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ use protos::services::{
BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest,
}; };
use protos::services_grpc::BeaconBlockServiceClient; use protos::services_grpc::BeaconBlockServiceClient;
use ssz::{ssz_encode, Decodable}; use ssz::{decode, ssz_encode};
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature, Slot}; use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature, Slot};
@ -41,10 +41,10 @@ impl BeaconNode for BeaconBlockGrpcClient {
if reply.has_block() { if reply.has_block() {
let block = reply.get_block(); let block = reply.get_block();
let (signature, _) = Signature::ssz_decode(block.get_signature(), 0) let signature = decode::<Signature>(block.get_signature())
.map_err(|_| BeaconNodeError::DecodeFailure)?; .map_err(|_| BeaconNodeError::DecodeFailure)?;
let (randao_reveal, _) = Signature::ssz_decode(block.get_randao_reveal(), 0) let randao_reveal = decode::<Signature>(block.get_randao_reveal())
.map_err(|_| BeaconNodeError::DecodeFailure)?; .map_err(|_| BeaconNodeError::DecodeFailure)?;
// TODO: this conversion is incomplete; fix it. // TODO: this conversion is incomplete; fix it.