/* * This is a WIP of implementing an alternative * serialization strategy. It attempts to follow Vitalik's * "simpleserialize" format here: * https://github.com/ethereum/beacon_chain/blob/master/beacon_chain/utils/simpleserialize.py * * This implementation is not final and would almost certainly * have issues. */ extern crate bytes; extern crate ethereum_types; mod cached_tree_hash; pub mod decode; pub mod encode; mod signed_root; pub mod tree_hash; mod impl_decode; mod impl_encode; mod impl_tree_hash; 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}; pub use hashing::hash; pub const LENGTH_BYTES: usize = 4; pub const MAX_LIST_SIZE: usize = 1 << (4 * 8); /// Convenience function to SSZ encode an object supporting ssz::Encode. pub fn ssz_encode(val: &T) -> Vec where T: Encodable, { let mut ssz_stream = SszStream::new(); 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::() will fail for all invalid cases if test_case["valid"].as_bool().unwrap() { // Convert test vector 'ssz' encoded yaml to Vec 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; match test_case["type"].as_str().unwrap() { "uint8" => { let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // check encoding // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint16" => { let value: u16 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint32" => { let value: u32 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint64" => { let value: u64 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&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::() will fail for all invalid cases if test_case["valid"].as_bool().unwrap() { // Convert test vector 'ssz' encoded yaml to Vec 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; match test_case["type"].as_str().unwrap() { "uint8" => { let value: u8 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // check encoding // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint16" => { let value: u16 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint32" => { let value: u32 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&test_vector_bytes).unwrap(); assert_eq!(decoded, value); } "uint64" => { let value: u64 = test_case["value"].as_str().unwrap().parse::().unwrap(); bytes = ssz_encode::(&value); // Check decoding let decoded = decode::(&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 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::(&test_vector_bytes); assert!(decoded.is_err()); } "uint16" => { let decoded = decode::(&test_vector_bytes); assert!(decoded.is_err()); } "uint32" => { let decoded = decode::(&test_vector_bytes); assert!(decoded.is_err()); } "uint64" => { let decoded = decode::(&test_vector_bytes); assert!(decoded.is_err()); } _ => continue, }; } } }