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::{ClientDB, DBError};
use ssz::Decodable;
use ssz::decode;
use std::sync::Arc;
use types::{BeaconBlock, Hash256, Slot};
@ -30,7 +30,7 @@ impl<T: ClientDB> BeaconBlockStore<T> {
match self.get(&hash)? {
None => Ok(None),
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(),
})?;
Ok(Some(block))

View File

@ -1,6 +1,6 @@
use super::STATES_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError};
use ssz::Decodable;
use ssz::decode;
use std::sync::Arc;
use types::{BeaconState, Hash256};
@ -23,7 +23,7 @@ impl<T: ClientDB> BeaconStateStore<T> {
match self.get(&hash)? {
None => Ok(None),
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(),
})?;
Ok(Some(state))

View File

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

View File

@ -6,7 +6,7 @@ use protos::services::{
};
use protos::services_grpc::ValidatorService;
use slog::{debug, Logger};
use ssz::Decodable;
use ssz::decode;
#[derive(Clone)]
pub struct ValidatorServiceInstance {
@ -20,7 +20,7 @@ impl ValidatorService for ValidatorServiceInstance {
req: PublicKeyRequest,
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());
let mut resp = IndexResponse::new();

View File

@ -130,4 +130,15 @@ mod epoch_tests {
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]
pub fn test_ssz_round_trip() {
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 original = $type::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = $type::ssz_decode(&bytes, 0).unwrap();
let decoded: $type = decode(&bytes).unwrap();
assert_eq!(original, decoded);
}

View File

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

View File

@ -6,7 +6,6 @@ mod aggregate_signature;
mod keypair;
mod public_key;
mod secret_key;
mod serde_vistors;
mod signature;
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_hex::{encode as hex_encode, PrefixedHexVisitor};
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::hash::{Hash, Hasher};
@ -90,9 +91,9 @@ impl<'de> Deserialize<'de> for PublicKey {
D: Deserializer<'de>,
{
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)))?;
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 hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
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.
///
@ -59,9 +61,9 @@ impl<'de> Deserialize<'de> for SecretKey {
D: Deserializer<'de>,
{
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)))?;
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 bls_aggregates::Signature as RawSignature;
use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::HexVisitor;
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.
@ -136,7 +137,7 @@ impl<'de> Deserialize<'de> for Signature {
where
D: Deserializer<'de>,
{
let bytes: Vec<u8> = deserializer.deserialize_str(HexVisitor)?;
let bytes = deserializer.deserialize_str(HexVisitor)?;
let signature = Signature::from_bytes(&bytes[..])
.map_err(|e| serde::de::Error::custom(format!("invalid ssz ({:?})", e)))?;
Ok(signature)
@ -156,7 +157,7 @@ mod tests {
let original = Signature::new(&[42, 42], 0, &keypair.sk);
let bytes = ssz_encode(&original);
let (decoded, _) = Signature::ssz_decode(&bytes, 0).unwrap();
let decoded = decode::<Signature>(&bytes).unwrap();
assert_eq!(original, decoded);
}

View File

@ -6,7 +6,7 @@ use bit_vec::BitVec;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode, PrefixedHexVisitor};
use ssz::Decodable;
use ssz::{Decodable, Encodable};
use std::cmp;
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.
fn ssz_append(&self, s: &mut ssz::SszStream) {
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> {
let len = ssz::decode::decode_length(bytes, index, ssz::LENGTH_BYTES)?;
if (ssz::LENGTH_BYTES + len) > bytes.len() {
@ -210,7 +210,7 @@ impl ssz::TreeHash for BooleanBitfield {
#[cfg(test)]
mod tests {
use super::*;
use ssz::{ssz_encode, Decodable, SszStream};
use ssz::{decode, ssz_encode, SszStream};
#[test]
fn test_new_bitfield() {
@ -378,12 +378,12 @@ mod tests {
let mut stream = SszStream::new();
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 mut stream = SszStream::new();
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 {
@ -399,13 +399,13 @@ mod tests {
#[test]
fn test_ssz_decode() {
let encoded = vec![0, 0, 0, 2, 225, 192];
let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap();
let encoded = vec![2, 0, 0, 0, 225, 192];
let field = decode::<BooleanBitfield>(&encoded).unwrap();
let expected = create_test_bitfield();
assert_eq!(field, expected);
let encoded = vec![0, 0, 0, 3, 255, 255, 3];
let (field, _): (BooleanBitfield, usize) = ssz::decode_ssz(&encoded, 0).unwrap();
let encoded = vec![3, 0, 0, 0, 255, 255, 3];
let field = decode::<BooleanBitfield>(&encoded).unwrap();
let expected = BooleanBitfield::from_bytes(&[255, 255, 3]);
assert_eq!(field, expected);
}
@ -414,7 +414,7 @@ mod tests {
fn test_ssz_round_trip() {
let original = BooleanBitfield::from_bytes(&vec![18; 12][..]);
let ssz = ssz_encode(&original);
let (decoded, _) = BooleanBitfield::ssz_decode(&ssz, 0).unwrap();
let decoded = decode::<BooleanBitfield>(&ssz).unwrap();
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)]
mod test {
use super::*;

View File

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

View File

@ -69,7 +69,7 @@ Syntax:
| Shorthand | Meaning |
|:-------------|:----------------------------------------------------|
| `big` | ``big endian`` |
| `little` | ``little endian`` |
| `to_bytes` | convert to bytes. Params: ``(size, byte order)`` |
| `from_bytes` | convert from bytes. Params: ``(bytes, byte order)`` |
| `value` | the value to serialize |
@ -82,7 +82,7 @@ Syntax:
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 |
|:-----------------------|:------------------------|
@ -92,7 +92,7 @@ All integers are serialized as **big endian**.
```python
buffer_size = int_size / 8
return value.to_bytes(buffer_size, 'big')
return value.to_bytes(buffer_size, 'little')
```
#### Address
@ -131,7 +131,7 @@ For general `byte` type:
value_bytes ]``
```python
byte_length = (len(value)).to_bytes(4, 'big')
byte_length = (len(value)).to_bytes(4, 'little')
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
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
byte_length = int_size / 8
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
@ -206,7 +206,7 @@ return rawbytes[current_index:current_index+32], new_index
Get the length of the bytes, return the bytes.
```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
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`` |
```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
item_index = current_index + 4
deserialized_list = []

View File

@ -9,7 +9,7 @@ publish = false
cargo-fuzz = true
[dependencies]
ethereum-types = "0.4.0"
ethereum-types = "0.5"
[dependencies.ssz]
path = ".."
@ -84,22 +84,22 @@ path = "fuzz_targets/fuzz_target_address_decode.rs"
name = "fuzz_target_address_encode"
path = "fuzz_targets/fuzz_target_address_encode.rs"
[[bin]]
name = "fuzz_target_vec_decode"
path = "fuzz_targets/fuzz_target_vec_decode.rs"
[[bin]]
name = "fuzz_target_vec_address_decode"
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]]
name = "fuzz_target_vec_bool_decode"
path = "fuzz_targets/fuzz_target_vec_bool_decode.rs"
[[bin]]
name = "fuzz_target_vec_decode"
path = "fuzz_targets/fuzz_target_vec_decode.rs"
[[bin]]
name = "fuzz_target_vec_encode"
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;
use ethereum_types::Address;
use ssz::{DecodeError, Decodable};
use ssz::{DecodeError, decode};
// Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| {
let result: Result<(Address, usize), DecodeError> = Decodable::ssz_decode(data, 0);
if data.len() >= 20 {
let result: Result<Address, DecodeError> = decode(data);
if data.len() == 20 {
// Should have valid result
let (address, index) = result.unwrap();
assert_eq!(index, 20);
let address = result.unwrap();
assert_eq!(address, Address::from_slice(&data[..20]));
} else {
// 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;
extern crate ssz;
use ssz::{DecodeError, Decodable};
use ssz::{DecodeError, decode};
// Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| {
let result: Result<(bool, usize), DecodeError> = Decodable::ssz_decode(data, 0);
if data.len() >= 1 {
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
if data[0] == u8::pow(2,7) {
let (val_bool, index) = result.unwrap();
let result: Result<bool, DecodeError> = decode(data);
if data.len() == 1 {
if data[0] == 1 {
let val_bool = result.unwrap();
assert!(val_bool);
assert_eq!(index, 1);
} else if data[0] == 0 {
let (val_bool, index) = result.unwrap();
let val_bool = result.unwrap();
assert!(!val_bool);
assert_eq!(index, 1);
} else {
assert_eq!(result, Err(DecodeError::Invalid));
}
} else {
// 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);
let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
assert_eq!(val_bool, ssz[0] % u8::pow(2, 6));
assert_eq!(val_bool, ssz[0]);
assert_eq!(ssz.len(), 1);
});

View File

@ -4,18 +4,17 @@ extern crate ethereum_types;
extern crate ssz;
use ethereum_types::H256;
use ssz::{DecodeError, Decodable};
use ssz::{DecodeError, decode};
// Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| {
let result: Result<(H256, usize), DecodeError> = Decodable::ssz_decode(data, 0);
if data.len() >= 32 {
let result: Result<H256, DecodeError> = decode(data);
if data.len() == 32 {
// Should have valid result
let (hash, index) = result.unwrap();
assert_eq!(index, 32);
let hash = result.unwrap();
assert_eq!(hash, H256::from_slice(&data[..32]));
} else {
// 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;
extern crate ssz;
use ssz::{DecodeError, Decodable};
use ssz::{DecodeError, decode};
// Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| {
let result: Result<(u16, usize), DecodeError> = Decodable::ssz_decode(data, 0);
if data.len() >= 2 {
let result: Result<u16, DecodeError> = decode(data);
if data.len() == 2 {
// Valid result
let (number_u16, index) = result.unwrap();
assert_eq!(index, 2);
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
let val = u16::from_be_bytes([data[0], data[1]]);
let number_u16 = result.unwrap();
let val = u16::from_le_bytes([data[0], data[1]]);
assert_eq!(number_u16, val);
} else {
// 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);
let ssz = ssz.drain();
// TODO: change to little endian bytes
// https://github.com/sigp/lighthouse/issues/215
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;
extern crate ssz;
use ssz::{DecodeError, Decodable};
use ssz::{DecodeError, decode};
// Fuzz ssz_decode()
fuzz_target!(|data: &[u8]| {
let result: Result<(u32, usize), DecodeError> = Decodable::ssz_decode(data, 0);
if data.len() >= 4 {
let result: Result<u32, DecodeError> = decode(data);
if data.len() == 4 {
// Valid result
let (number_u32, index) = result.unwrap();
assert_eq!(index, 4);
// 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]]);
let number_u32 = result.unwrap();
let val = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
assert_eq!(number_u32, val);
} else {
// Length less then 4 should return error
assert_eq!(result, Err(DecodeError::TooShort));
// Length not 4 should return error
assert!(result.is_err());
}
});

View File

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

View File

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

View File

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

View File

@ -15,8 +15,6 @@ fuzz_target!(|data: &[u8]| {
ssz.append(&number_u8);
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!(ssz.len(), 1);
});

View File

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

View File

@ -4,9 +4,9 @@ extern crate ethereum_types;
extern crate ssz;
use ethereum_types::{Address};
use ssz::{DecodeError, Decodable};
use ssz::{decode, DecodeError};
// Fuzz ssz_decode()
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;
extern crate ssz;
use ssz::{DecodeError, Decodable};
use ssz::{decode, DecodeError};
// Fuzz ssz_decode()
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 ssz;
use ethereum_types::{Address, H256};
use ssz::{DecodeError, Decodable};
use ssz::{decode, DecodeError, Decodable};
// Fuzz ssz_decode()
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 ssz;
use ethereum_types::{Address, H256};
use ssz::SszStream;
// Fuzz ssz_encode()

View File

@ -2,9 +2,9 @@
#[macro_use] extern crate libfuzzer_sys;
extern crate ssz;
use ssz::{DecodeError, Decodable};
use ssz::{decode, DecodeError};
// Fuzz ssz_decode()
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
///
/// The single ssz encoded value will be decoded as the given type at the
/// given index.
pub fn decode_ssz<T>(ssz_bytes: &[u8], index: usize) -> Result<(T, usize), DecodeError>
/// The single ssz encoded value/container/list will be decoded as the given type,
/// by recursively calling `ssz_decode`.
pub fn decode<T>(ssz_bytes: &[u8]) -> Result<(T), DecodeError>
where
T: Decodable,
{
if index >= ssz_bytes.len() {
return Err(DecodeError::TooShort);
let (decoded, i): (T, usize) = match T::ssz_decode(ssz_bytes, 0) {
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.
@ -65,7 +71,7 @@ where
}
/// 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.
pub fn decode_length(
bytes: &[u8],
@ -82,7 +88,7 @@ pub fn decode_length(
.take(index + length_bytes)
.skip(index)
{
let offset = (index + length_bytes - i - 1) * 8;
let offset = (i - index) * 8;
len |= (*byte as usize) << offset;
}
Ok(len)
@ -90,18 +96,18 @@ pub fn decode_length(
#[cfg(test)]
mod tests {
use super::super::encode::encode_length;
use super::super::encode::*;
use super::*;
#[test]
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);
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);
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);
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]
fn test_decode_ssz_list() {
// u16
let v: Vec<u16> = vec![10, 10, 10, 10];
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.1, 12);
assert_eq!(decoded.1, LENGTH_BYTES + (4 * 2));
// u32
let v: Vec<u32> = vec![10, 10, 10, 10];
let decoded: (Vec<u32>, usize) = decode_ssz_list(
&vec![
0, 0, 0, 16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10,
16, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 00,
],
0,
)
@ -158,36 +178,37 @@ mod tests {
let v: Vec<u64> = vec![10, 10, 10, 10];
let decoded: (Vec<u64>, usize) = decode_ssz_list(
&vec![
0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0, 10,
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,
0, 0, 10, 0, 0, 0, 0, 0, 0, 0,
],
0,
)
.unwrap();
assert_eq!(decoded.0, v);
assert_eq!(decoded.1, 36);
assert_eq!(decoded.1, LENGTH_BYTES + (8 * 4));
// Check that it can accept index
let v: Vec<usize> = vec![15, 15, 15, 15];
let offset = 10;
let decoded: (Vec<usize>, usize) = decode_ssz_list(
&vec![
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0,
0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15,
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, 0, 15, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0,
],
10,
offset,
)
.unwrap();
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
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));
// Check that incorrect index throws error
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));
}
}

View File

@ -70,13 +70,13 @@ impl SszStream {
/// Encode some length into a ssz size prefix.
///
/// 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> {
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 = (length_bytes - i - 1) * 8;
let offset = i * 8;
*header_byte = ((len >> offset) & 0xff) as u8;
}
header
@ -95,15 +95,27 @@ mod tests {
#[test]
fn test_encode_length_4_bytes() {
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(255, LENGTH_BYTES), vec![0, 0, 0, 255]);
assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 0, 1, 0]);
assert_eq!(encode_length(1, LENGTH_BYTES), vec![1, 0, 0, 0]);
assert_eq!(encode_length(255, LENGTH_BYTES), vec![255, 0, 0, 0]);
assert_eq!(encode_length(256, LENGTH_BYTES), vec![0, 1, 0, 0]);
assert_eq!(
encode_length(4294967295, LENGTH_BYTES), // 2^(3*8) - 1
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]
#[should_panic]
fn test_encode_length_4_bytes_panic() {
@ -117,8 +129,42 @@ mod tests {
stream.append_vec(&test_vec);
let ssz = stream.drain();
assert_eq!(ssz.len(), 4 + (12 * 2));
assert_eq!(ssz[0..4], *vec![0, 0, 0, 24]);
assert_eq!(ssz[4..6], *vec![1, 0]);
assert_eq!(ssz.len(), LENGTH_BYTES + (12 * 2));
assert_eq!(ssz[0..4], *vec![24, 0, 0, 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 mut result: $type = 0;
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;
}
Ok((result, end_bytes))
@ -65,7 +65,7 @@ impl Decodable for bool {
} else {
let result = match bytes[index] {
0b0000_0000 => false,
0b1000_0000 => true,
0b0000_0001 => true,
_ => return Err(DecodeError::Invalid),
};
Ok((result, index + 1))
@ -104,7 +104,7 @@ where
#[cfg(test)]
mod tests {
use super::super::{decode_ssz, DecodeError};
use super::super::{decode, DecodeError};
use super::*;
#[test]
@ -138,139 +138,169 @@ mod tests {
fn test_ssz_decode_u16() {
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!(index, 2);
let ssz = vec![0, 16];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap();
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![1, 0];
let (result, index): (u16, usize) = decode_ssz(&ssz, 0).unwrap();
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) = decode_ssz(&ssz, 0).unwrap();
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> = decode_ssz(&ssz, 0);
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) = decode_ssz(&ssz, 0).unwrap();
let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(result, 0);
assert_eq!(index, 4);
let ssz = vec![0, 0, 1, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap();
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, 0, 1, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 3).unwrap();
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, 200, 1, 0];
let (result, index): (u32, usize) = decode_ssz(&ssz, 0).unwrap();
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) = decode_ssz(&ssz, 0).unwrap();
let (result, index): (u32, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 4);
assert_eq!(result, 4294967295);
let ssz = vec![0, 0, 1];
let result: Result<(u32, usize), DecodeError> = decode_ssz(&ssz, 0);
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) = decode_ssz(&ssz, 0).unwrap();
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) = decode_ssz(&ssz, 0).unwrap();
let (result, index): (u64, usize) = <_>::ssz_decode(&ssz, 0).unwrap();
assert_eq!(index, 8);
assert_eq!(result, 18446744073709551615);
let ssz = vec![0, 0, 8, 255, 0, 0, 0, 0, 0, 0, 0];
let (result, index): (u64, usize) = decode_ssz(&ssz, 3).unwrap();
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> = decode_ssz(&ssz, 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) = decode_ssz(&ssz, 0).unwrap();
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) = decode_ssz(&ssz, 3).unwrap();
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) = decode_ssz(&ssz, 0).unwrap();
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> = decode_ssz(&ssz, 0);
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> = decode_ssz(&vec![1], 2);
let err: Result<(u16, usize), DecodeError> = <_>::ssz_decode(&vec![1], 2);
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));
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);
}
#[test]
fn test_decode_ssz_bool() {
let ssz = vec![0b0000_0000, 0b1000_0000];
let (result, index): (bool, usize) = decode_ssz(&ssz, 0).unwrap();
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) = decode_ssz(&ssz, 1).unwrap();
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> = decode_ssz(&ssz, 0);
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, index): ([u8; 4], usize) = decode_ssz(&ssz, 0).unwrap();
assert_eq!(index, 4);
let result: [u8; 4] = decode(&ssz).unwrap();
assert_eq!(result.len(), 4);
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 {
8 => buf.put_u8(*self as u8),
16 => buf.put_u16_be(*self as u16),
32 => buf.put_u32_be(*self as u32),
64 => buf.put_u64_be(*self as u64),
16 => buf.put_u16_le(*self as u16),
32 => buf.put_u32_le(*self as u32),
64 => buf.put_u64_le(*self as u64),
_ => {}
}
@ -61,7 +61,7 @@ impl_encodable_for_u8_array!(4);
impl Encodable for bool {
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]);
}
}
@ -136,17 +136,17 @@ mod tests {
let x: u16 = 1;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 1]);
assert_eq!(ssz.drain(), vec![1, 0]);
let x: u16 = 100;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0, 100]);
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![1, 0]);
assert_eq!(ssz.drain(), vec![0, 1]);
let x: u16 = 65535;
let mut ssz = SszStream::new();
@ -159,22 +159,22 @@ mod tests {
let x: u32 = 1;
let mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
@ -187,17 +187,17 @@ mod tests {
let x: u64 = 1;
let mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
@ -210,17 +210,17 @@ mod tests {
let x: usize = 1;
let mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
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 mut ssz = SszStream::new();
@ -228,6 +228,27 @@ mod tests {
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;
@ -238,7 +259,7 @@ mod tests {
let x: bool = true;
let mut ssz = SszStream::new();
ssz.append(&x);
assert_eq!(ssz.drain(), vec![0b1000_0000]);
assert_eq!(ssz.drain(), vec![0b0000_0001]);
}
#[test]

View File

@ -19,7 +19,7 @@ mod impl_decode;
mod impl_encode;
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::signed_root::SignedRoot;
pub use crate::tree_hash::{merkle_hash, TreeHash};
@ -38,3 +38,193 @@ where
ssz_stream.append(val);
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,
};
use protos::services_grpc::BeaconBlockServiceClient;
use ssz::{ssz_encode, Decodable};
use ssz::{decode, ssz_encode};
use std::sync::Arc;
use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature, Slot};
@ -41,10 +41,10 @@ impl BeaconNode for BeaconBlockGrpcClient {
if reply.has_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)?;
let (randao_reveal, _) = Signature::ssz_decode(block.get_randao_reveal(), 0)
let randao_reveal = decode::<Signature>(block.get_randao_reveal())
.map_err(|_| BeaconNodeError::DecodeFailure)?;
// TODO: this conversion is incomplete; fix it.