From 4aa6d57abe04f5a63a20517eaf8fc003a3a50c81 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 15 May 2019 15:08:48 +1000 Subject: [PATCH] Improve `ef_tests`, pass all ssz_static tests --- tests/ef_tests/Cargo.toml | 3 + tests/ef_tests/src/cases/ssz_static.rs | 22 +++++--- tests/ef_tests/src/doc.rs | 9 ++- tests/ef_tests/src/eth_specs.rs | 9 ++- tests/ef_tests/tests/tests.rs | 78 ++++++++++++-------------- 5 files changed, 67 insertions(+), 54 deletions(-) diff --git a/tests/ef_tests/Cargo.toml b/tests/ef_tests/Cargo.toml index 08cf279b56..b7596755de 100644 --- a/tests/ef_tests/Cargo.toml +++ b/tests/ef_tests/Cargo.toml @@ -11,10 +11,13 @@ fake_crypto = ["bls/fake_crypto"] bls = { path = "../../eth2/utils/bls" } ethereum-types = "0.5" hex = "0.3" +rayon = "1.0" serde = "1.0" serde_derive = "1.0" serde_yaml = "0.8" ssz = { path = "../../eth2/utils/ssz" } tree_hash = { path = "../../eth2/utils/tree_hash" } +cached_tree_hash = { path = "../../eth2/utils/cached_tree_hash" } types = { path = "../../eth2/types" } +walkdir = "2" yaml-rust = { git = "https://github.com/sigp/yaml-rust", branch = "escape_all_str"} diff --git a/tests/ef_tests/src/cases/ssz_static.rs b/tests/ef_tests/src/cases/ssz_static.rs index f2211922f4..3957bd81ac 100644 --- a/tests/ef_tests/src/cases/ssz_static.rs +++ b/tests/ef_tests/src/cases/ssz_static.rs @@ -1,5 +1,7 @@ use super::*; use crate::case_result::compare_result; +use cached_tree_hash::{CachedTreeHash, TreeHashCache}; +use rayon::prelude::*; use serde_derive::Deserialize; use ssz::Decode; use std::fmt::Debug; @@ -48,7 +50,7 @@ impl SszStatic { impl EfTest for Cases { fn test_results(&self) -> Vec { self.test_cases - .iter() + .par_iter() .enumerate() .map(|(i, tc)| { let result = match tc.type_name.as_ref() { @@ -88,7 +90,7 @@ impl EfTest for Cases { fn ssz_static_test(tc: &SszStatic) -> Result<(), Error> where - T: Decode + Debug + PartialEq + serde::de::DeserializeOwned + TreeHash, + T: Decode + Debug + PartialEq + serde::de::DeserializeOwned + TreeHash + CachedTreeHash, { // Verify we can decode SSZ in the same way we can decode YAML. let ssz = hex::decode(&tc.serialized[2..]) @@ -97,12 +99,18 @@ where let decode_result = T::from_ssz_bytes(&ssz); compare_result(&decode_result, &Some(expected))?; - // Verify the tree hash root is identical to the decoded struct. - let root_bytes = + // Verify the TreeHash root of the decoded struct matches the test. + let decoded = decode_result.unwrap(); + let expected_root = &hex::decode(&tc.root[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; - let expected_root = Hash256::from_slice(&root_bytes); - let root = Hash256::from_slice(&decode_result.unwrap().tree_hash_root()); - compare_result::(&Ok(root), &Some(expected_root))?; + let expected_root = Hash256::from_slice(&expected_root); + let tree_hash_root = Hash256::from_slice(&decoded.tree_hash_root()); + compare_result::(&Ok(tree_hash_root), &Some(expected_root))?; + + // Verify a _new_ CachedTreeHash root of the decoded struct matches the test. + let cache = TreeHashCache::new(&decoded).unwrap(); + let cached_tree_hash_root = Hash256::from_slice(cache.tree_hash_root().unwrap()); + compare_result::(&Ok(cached_tree_hash_root), &Some(expected_root))?; Ok(()) } diff --git a/tests/ef_tests/src/doc.rs b/tests/ef_tests/src/doc.rs index 535b85f297..1a93c738a7 100644 --- a/tests/ef_tests/src/doc.rs +++ b/tests/ef_tests/src/doc.rs @@ -1,12 +1,12 @@ use crate::case_result::CaseResult; use crate::cases::*; use crate::doc_header::DocHeader; -use crate::eth_specs::MinimalEthSpec; +use crate::eth_specs::{MainnetEthSpec, MinimalEthSpec}; use crate::yaml_decode::{extract_yaml_by_key, YamlDecode}; use crate::EfTest; use serde_derive::Deserialize; use std::{fs::File, io::prelude::*, path::PathBuf}; -use types::{EthSpec, FoundationEthSpec}; +use types::EthSpec; #[derive(Debug, Deserialize)] pub struct Doc { @@ -32,8 +32,9 @@ impl Doc { header.handler.as_ref(), header.config.as_ref(), ) { - ("ssz", "uint", _) => run_test::(&self.yaml), + ("ssz", "uint", _) => run_test::(&self.yaml), ("ssz", "static", "minimal") => run_test::(&self.yaml), + ("ssz", "static", "mainnet") => run_test::(&self.yaml), (runner, handler, config) => panic!( "No implementation for runner: \"{}\", handler: \"{}\", config: \"{}\"", runner, handler, config @@ -48,6 +49,8 @@ impl Doc { if results.iter().any(|r| r.result.is_err()) { print_failures(&doc, &results); panic!("Tests failed (see above)"); + } else { + println!("Passed {} tests in {:?}", results.len(), doc.path); } } } diff --git a/tests/ef_tests/src/eth_specs.rs b/tests/ef_tests/src/eth_specs.rs index 81a6e1731f..b2d46d8bcb 100644 --- a/tests/ef_tests/src/eth_specs.rs +++ b/tests/ef_tests/src/eth_specs.rs @@ -1,5 +1,8 @@ -use types::{EthSpec, typenum::{U64, U8}, ChainSpec, FewValidatorsEthSpec}; -use serde_derive::{Serialize, Deserialize}; +use serde_derive::{Deserialize, Serialize}; +use types::{ + typenum::{U64, U8}, + ChainSpec, EthSpec, FewValidatorsEthSpec, FoundationEthSpec, +}; /// "Minimal" testing specification, as defined here: /// @@ -21,3 +24,5 @@ impl EthSpec for MinimalEthSpec { FewValidatorsEthSpec::spec() } } + +pub type MainnetEthSpec = FoundationEthSpec; diff --git a/tests/ef_tests/tests/tests.rs b/tests/ef_tests/tests/tests.rs index 2497c801df..ebdace0a8a 100644 --- a/tests/ef_tests/tests/tests.rs +++ b/tests/ef_tests/tests/tests.rs @@ -1,51 +1,45 @@ use ef_tests::*; +use rayon::prelude::*; use std::path::PathBuf; +use walkdir::WalkDir; -fn test_file(trailing_path: &str) -> PathBuf { - let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push(format!("eth2.0-spec-tests/tests/{}", trailing_path)); +fn yaml_files_in_test_dir(dir: &str) -> Vec { + let mut base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + base_path.push("eth2.0-spec-tests"); + base_path.push("tests"); + base_path.push(dir); - file_path_buf + WalkDir::new(base_path) + .into_iter() + .filter_map(|e| e.ok()) + .filter_map(|entry| { + if entry.file_type().is_file() { + match entry.file_name().to_str() { + Some(f) if f.ends_with(".yaml") => Some(entry.path().to_path_buf()), + Some(f) if f.ends_with(".yml") => Some(entry.path().to_path_buf()), + _ => None, + } + } else { + None + } + }) + .collect() } -mod ssz_generic { - use super::*; - - fn ssz_generic_file(file: &str) -> PathBuf { - let mut path = test_file("ssz_generic"); - path.push(file); - - path - } - - #[test] - fn uint_bounds() { - Doc::assert_tests_pass(ssz_generic_file("uint/uint_bounds.yaml")); - } - - #[test] - fn uint_random() { - Doc::assert_tests_pass(ssz_generic_file("uint/uint_random.yaml")); - } - - #[test] - fn uint_wrong_length() { - Doc::assert_tests_pass(ssz_generic_file("uint/uint_wrong_length.yaml")); - } +#[test] +fn ssz_generic() { + yaml_files_in_test_dir("ssz_generic") + .into_par_iter() + .for_each(|file| { + Doc::assert_tests_pass(file); + }); } -mod ssz_static { - use super::*; - - fn ssz_generic_file(file: &str) -> PathBuf { - let mut path = test_file("ssz_static"); - path.push(file); - - path - } - - #[test] - fn minimal_nil() { - Doc::assert_tests_pass(ssz_generic_file("core/ssz_minimal_nil.yaml")); - } +#[test] +fn ssz_static() { + yaml_files_in_test_dir("ssz_static") + .into_par_iter() + .for_each(|file| { + Doc::assert_tests_pass(file); + }); }