BLS and SSZ static tests

This commit is contained in:
Michael Sproul 2019-08-28 18:46:16 +10:00
parent aed2f6407d
commit 23a308e595
No known key found for this signature in database
GPG Key ID: 77B1309D2E54E914
16 changed files with 481 additions and 178 deletions

View File

@ -4,25 +4,13 @@ use crate::{Checkpoint, Crosslink, Hash256};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// The data upon which an attestation is based.
///
/// Spec v0.8.0
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
Hash,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom,
)]
pub struct AttestationData {
// LMD GHOST vote

View File

@ -4,7 +4,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// Casper FFG checkpoint, used in attestations.
///
@ -22,7 +22,6 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
pub struct Checkpoint {
pub epoch: Epoch,

View File

@ -1,5 +1,6 @@
use super::*;
use std::fmt::Debug;
use std::path::Path;
mod bls_aggregate_pubkeys;
mod bls_aggregate_sigs;
@ -53,6 +54,11 @@ pub use shuffling::*;
pub use ssz_generic::*;
pub use ssz_static::*;
pub trait LoadCase: Sized {
/// Load the test case from a test case directory.
fn load_from_dir(_path: &Path) -> Result<Self, Error>;
}
pub trait Case: Debug {
/// An optional field for implementing a custom description.
///
@ -68,6 +74,26 @@ pub trait Case: Debug {
fn result(&self, case_index: usize) -> Result<(), Error>;
}
pub trait BlsCase: serde::de::DeserializeOwned {}
impl<T> YamlDecode for T
where
T: BlsCase,
{
fn yaml_decode(string: &str) -> Result<Self, Error> {
serde_yaml::from_str(string).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))
}
}
impl<T> LoadCase for T
where
T: BlsCase,
{
fn load_from_dir(path: &Path) -> Result<Self, Error> {
Self::yaml_decode_file(&path.join("data.yaml"))
}
}
#[derive(Debug)]
pub struct Cases<T> {
pub test_cases: Vec<T>,
@ -86,6 +112,7 @@ where
}
}
// FIXME(michael): delete this
impl<T: YamlDecode> YamlDecode for Cases<T> {
/// Decodes a YAML list of test cases
fn yaml_decode(yaml: &str) -> Result<Self, Error> {

View File

@ -9,11 +9,7 @@ pub struct BlsAggregatePubkeys {
pub output: String,
}
impl YamlDecode for BlsAggregatePubkeys {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl BlsCase for BlsAggregatePubkeys {}
impl Case for BlsAggregatePubkeys {
fn result(&self, _case_index: usize) -> Result<(), Error> {

View File

@ -9,11 +9,7 @@ pub struct BlsAggregateSigs {
pub output: String,
}
impl YamlDecode for BlsAggregateSigs {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl BlsCase for BlsAggregateSigs {}
impl Case for BlsAggregateSigs {
fn result(&self, _case_index: usize) -> Result<(), Error> {

View File

@ -15,11 +15,7 @@ pub struct BlsG2Compressed {
pub output: Vec<String>,
}
impl YamlDecode for BlsG2Compressed {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl BlsCase for BlsG2Compressed {}
impl Case for BlsG2Compressed {
fn result(&self, _case_index: usize) -> Result<(), Error> {

View File

@ -9,11 +9,7 @@ pub struct BlsPrivToPub {
pub output: String,
}
impl YamlDecode for BlsPrivToPub {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl BlsCase for BlsPrivToPub {}
impl Case for BlsPrivToPub {
fn result(&self, _case_index: usize) -> Result<(), Error> {

View File

@ -16,11 +16,7 @@ pub struct BlsSign {
pub output: String,
}
impl YamlDecode for BlsSign {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl BlsCase for BlsSign {}
impl Case for BlsSign {
fn result(&self, _case_index: usize) -> Result<(), Error> {

View File

@ -3,125 +3,120 @@ use crate::case_result::compare_result;
use serde_derive::Deserialize;
use ssz::{Decode, Encode};
use std::fmt::Debug;
use std::marker::PhantomData;
use tree_hash::TreeHash;
use types::{
test_utils::TestRandom, Attestation, AttestationData, AttestationDataAndCustodyBit,
AttesterSlashing, BeaconBlock, BeaconBlockBody, BeaconBlockHeader, BeaconState, Checkpoint,
CompactCommittee, Crosslink, Deposit, DepositData, Eth1Data, EthSpec, Fork, Hash256,
HistoricalBatch, IndexedAttestation, PendingAttestation, ProposerSlashing, Transfer, Validator,
VoluntaryExit,
};
// Enum variant names are used by Serde when deserializing the test YAML
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Deserialize)]
pub enum SszStatic<E>
where
E: EthSpec,
{
Fork(SszStaticInner<Fork, E>),
Crosslink(SszStaticInner<Crosslink, E>),
Checkpoint(SszStaticInner<Checkpoint, E>),
CompactCommittee(SszStaticInner<CompactCommittee<E>, E>),
Eth1Data(SszStaticInner<Eth1Data, E>),
AttestationData(SszStaticInner<AttestationData, E>),
AttestationDataAndCustodyBit(SszStaticInner<AttestationDataAndCustodyBit, E>),
IndexedAttestation(SszStaticInner<IndexedAttestation<E>, E>),
DepositData(SszStaticInner<DepositData, E>),
BeaconBlockHeader(SszStaticInner<BeaconBlockHeader, E>),
Validator(SszStaticInner<Validator, E>),
PendingAttestation(SszStaticInner<PendingAttestation<E>, E>),
HistoricalBatch(SszStaticInner<HistoricalBatch<E>, E>),
ProposerSlashing(SszStaticInner<ProposerSlashing, E>),
AttesterSlashing(SszStaticInner<AttesterSlashing<E>, E>),
Attestation(SszStaticInner<Attestation<E>, E>),
Deposit(SszStaticInner<Deposit, E>),
VoluntaryExit(SszStaticInner<VoluntaryExit, E>),
Transfer(SszStaticInner<Transfer, E>),
BeaconBlockBody(SszStaticInner<BeaconBlockBody<E>, E>),
BeaconBlock(SszStaticInner<BeaconBlock<E>, E>),
BeaconState(SszStaticInner<BeaconState<E>, E>),
}
use std::fs;
use tree_hash::{SignedRoot, TreeHash};
use types::Hash256;
#[derive(Debug, Clone, Deserialize)]
pub struct SszStaticInner<T, E>
where
E: EthSpec,
{
pub value: T,
pub serialized: String,
pub root: String,
#[serde(skip, default)]
_phantom: PhantomData<E>,
struct SszStaticRoots {
root: String,
signing_root: Option<String>,
}
impl<E: EthSpec + serde::de::DeserializeOwned> YamlDecode for SszStatic<E> {
impl YamlDecode for SszStaticRoots {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
serde_yaml::from_str(yaml).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for SszStatic<E> {
fn result(&self, _case_index: usize) -> Result<(), Error> {
use self::SszStatic::*;
match *self {
Fork(ref val) => ssz_static_test(val),
Crosslink(ref val) => ssz_static_test(val),
Checkpoint(ref val) => ssz_static_test(val),
CompactCommittee(ref val) => ssz_static_test(val),
Eth1Data(ref val) => ssz_static_test(val),
AttestationData(ref val) => ssz_static_test(val),
AttestationDataAndCustodyBit(ref val) => ssz_static_test(val),
IndexedAttestation(ref val) => ssz_static_test(val),
DepositData(ref val) => ssz_static_test(val),
BeaconBlockHeader(ref val) => ssz_static_test(val),
Validator(ref val) => ssz_static_test(val),
PendingAttestation(ref val) => ssz_static_test(val),
HistoricalBatch(ref val) => ssz_static_test(val),
ProposerSlashing(ref val) => ssz_static_test(val),
AttesterSlashing(ref val) => ssz_static_test(val),
Attestation(ref val) => ssz_static_test(val),
Deposit(ref val) => ssz_static_test(val),
VoluntaryExit(ref val) => ssz_static_test(val),
Transfer(ref val) => ssz_static_test(val),
BeaconBlockBody(ref val) => ssz_static_test(val),
BeaconBlock(ref val) => ssz_static_test(val),
BeaconState(ref val) => ssz_static_test(val),
}
}
#[derive(Debug, Clone)]
pub struct SszStatic<T> {
roots: SszStaticRoots,
serialized: Vec<u8>,
value: T,
}
fn ssz_static_test<T, E: EthSpec>(tc: &SszStaticInner<T, E>) -> Result<(), Error>
where
T: Clone
+ Decode
+ Debug
+ Encode
+ PartialEq<T>
+ serde::de::DeserializeOwned
+ TreeHash
+ TestRandom,
#[derive(Debug, Clone)]
pub struct SszStaticSR<T> {
roots: SszStaticRoots,
serialized: Vec<u8>,
value: T,
}
// Trait alias for all deez bounds
pub trait SszStaticType:
serde::de::DeserializeOwned + Decode + Encode + TreeHash + Clone + PartialEq + Debug
{
// Verify we can decode SSZ in the same way we can decode YAML.
let ssz = hex::decode(&tc.serialized[2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let expected = tc.value.clone();
let decode_result = T::from_ssz_bytes(&ssz);
compare_result(&decode_result, &Some(expected))?;
}
// Verify we can encode the result back into original ssz bytes
let decoded = decode_result.unwrap();
let encoded_result = decoded.as_ssz_bytes();
compare_result::<Vec<u8>, Error>(&Ok(encoded_result), &Some(ssz))?;
impl<T> SszStaticType for T where
T: serde::de::DeserializeOwned + Decode + Encode + TreeHash + Clone + PartialEq + Debug
{
}
// Verify the TreeHash root of the decoded struct matches the test.
let expected_root =
&hex::decode(&tc.root[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let expected_root = Hash256::from_slice(&expected_root);
let tree_hash_root = Hash256::from_slice(&decoded.tree_hash_root());
compare_result::<Hash256, Error>(&Ok(tree_hash_root), &Some(expected_root))?;
fn load_from_dir<T: SszStaticType>(path: &Path) -> Result<(SszStaticRoots, Vec<u8>, T), Error> {
// FIXME: set description/name
let roots = SszStaticRoots::yaml_decode_file(&path.join("roots.yaml"))?;
let serialized = fs::read(&path.join("serialized.ssz")).expect("serialized.ssz exists");
let yaml = fs::read_to_string(&path.join("value.yaml")).expect("value.yaml exists");
let value =
serde_yaml::from_str(&yaml).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
Ok((roots, serialized, value))
}
impl<T: SszStaticType> LoadCase for SszStatic<T> {
fn load_from_dir(path: &Path) -> Result<Self, Error> {
load_from_dir(path).map(|(roots, serialized, value)| Self {
roots,
serialized,
value,
})
}
}
impl<T: SszStaticType + SignedRoot> LoadCase for SszStaticSR<T> {
fn load_from_dir(path: &Path) -> Result<Self, Error> {
load_from_dir(path).map(|(roots, serialized, value)| Self {
roots,
serialized,
value,
})
}
}
fn check_serialization<T: SszStaticType>(value: &T, serialized: &[u8]) -> Result<(), Error> {
// Check serialization
let serialized_result = value.as_ssz_bytes();
compare_result::<Vec<u8>, Error>(&Ok(serialized_result), &Some(serialized.to_vec()))?;
// Check deserialization
let deserialized_result = T::from_ssz_bytes(serialized);
compare_result(&deserialized_result, &Some(value.clone()))?;
Ok(())
}
fn check_tree_hash(expected_str: &str, actual_root: Vec<u8>) -> Result<(), Error> {
let expected_root = hex::decode(&expected_str[2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let expected_root = Hash256::from_slice(&expected_root);
let tree_hash_root = Hash256::from_slice(&actual_root);
compare_result::<Hash256, Error>(&Ok(tree_hash_root), &Some(expected_root))
}
impl<T: SszStaticType> Case for SszStatic<T> {
fn result(&self, _case_index: usize) -> Result<(), Error> {
check_serialization(&self.value, &self.serialized)?;
check_tree_hash(&self.roots.root, self.value.tree_hash_root())?;
Ok(())
}
}
impl<T: SszStaticType + SignedRoot> Case for SszStaticSR<T> {
fn result(&self, _case_index: usize) -> Result<(), Error> {
check_serialization(&self.value, &self.serialized)?;
check_tree_hash(&self.roots.root, self.value.tree_hash_root())?;
check_tree_hash(
&self
.roots
.signing_root
.as_ref()
.expect("signed root exists"),
self.value.signed_root(),
)?;
Ok(())
}
}

View File

@ -2,10 +2,14 @@ use crate::case_result::CaseResult;
use crate::cases::*;
use crate::doc_header::DocHeader;
use crate::error::Error;
use crate::yaml_decode::{yaml_split_header_and_cases, YamlDecode};
use crate::yaml_decode::YamlDecode;
use crate::EfTest;
use serde_derive::Deserialize;
use std::{fs::File, io::prelude::*, path::PathBuf};
use std::{
fs::File,
io::prelude::*,
path::{Path, PathBuf},
};
use types::{MainnetEthSpec, MinimalEthSpec};
#[derive(Debug, Deserialize)]
@ -19,15 +23,13 @@ impl Doc {
fn from_path(path: PathBuf) -> Self {
let mut file = File::open(path.clone()).unwrap();
let mut yaml = String::new();
file.read_to_string(&mut yaml).unwrap();
let (header_yaml, cases_yaml) = yaml_split_header_and_cases(yaml.clone());
let mut cases_yaml = String::new();
file.read_to_string(&mut cases_yaml).unwrap();
Self {
header_yaml,
cases_yaml,
path,
header_yaml: String::new(),
}
}
@ -40,8 +42,6 @@ impl Doc {
header.config.as_ref(),
) {
("ssz", "uint", _) => run_test::<SszGeneric>(self),
("ssz", "static", "minimal") => run_test::<SszStatic<MinimalEthSpec>>(self),
("ssz", "static", "mainnet") => run_test::<SszStatic<MainnetEthSpec>>(self),
("sanity", "slots", "minimal") => run_test::<SanitySlots<MinimalEthSpec>>(self),
// FIXME: skipped due to compact committees issue
("sanity", "slots", "mainnet") => vec![], // run_test::<SanitySlots<MainnetEthSpec>>(self),
@ -172,14 +172,36 @@ impl Doc {
}
}
pub fn run_test<T>(doc: &Doc) -> Vec<CaseResult>
pub fn assert_tests_pass(path: &Path, results: &[CaseResult]) {
let doc = Doc {
header_yaml: String::new(),
cases_yaml: String::new(),
path: path.into(),
};
let (failed, skipped_bls, skipped_known_failures) = categorize_results(results);
if failed.len() + skipped_known_failures.len() > 0 {
print_results(
&doc,
&failed,
&skipped_bls,
&skipped_known_failures,
&results,
);
if !failed.is_empty() {
panic!("Tests failed (see above)");
}
} else {
println!("Passed {} tests in {}", results.len(), path.display());
}
}
pub fn run_test<T>(_: &Doc) -> Vec<CaseResult>
where
Cases<T>: EfTest + YamlDecode,
{
// Pass only the "test_cases" YAML string to `yaml_decode`.
let test_cases: Cases<T> = Cases::yaml_decode(&doc.cases_yaml).unwrap();
test_cases.test_results()
panic!("FIXME(michael): delete this")
}
pub fn categorize_results(
@ -208,7 +230,6 @@ pub fn print_results(
skipped_known_failures: &[&CaseResult],
results: &[CaseResult],
) {
let header: DocHeader = serde_yaml::from_str(&doc.header_yaml).unwrap();
println!("--------------------------------------------------");
println!(
"Test {}",
@ -218,7 +239,7 @@ pub fn print_results(
"Failure"
}
);
println!("Title: {}", header.title);
println!("Title: TODO");
println!("File: {:?}", doc.path);
println!(
"{} tests, {} failed, {} skipped (known failure), {} skipped (bls), {} passed. (See below for errors)",

View File

@ -0,0 +1,130 @@
use crate::cases::{self, Case, Cases, LoadCase};
use crate::type_name::TypeName;
use crate::EfTest;
use std::fs;
use std::marker::PhantomData;
use std::path::PathBuf;
use tree_hash::SignedRoot;
pub trait Handler {
type Case: Case + LoadCase;
fn config_name() -> &'static str {
"general"
}
fn fork_name() -> &'static str {
"phase0"
}
fn runner_name() -> &'static str;
fn handler_name() -> &'static str;
fn run() {
let handler_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("eth2.0-spec-tests")
.join("tests")
.join(Self::config_name())
.join(Self::fork_name())
.join(Self::runner_name())
.join(Self::handler_name());
// Iterate through test suites
// TODO: parallelism
// TODO: error handling?
let test_cases = fs::read_dir(&handler_path)
.expect("open main directory")
.flat_map(|entry| {
entry
.ok()
.filter(|e| e.file_type().map(|ty| ty.is_dir()).unwrap_or(false))
})
.flat_map(|suite| fs::read_dir(suite.path()).expect("open suite dir"))
.flat_map(Result::ok)
.map(|test_case_dir| Self::Case::load_from_dir(&test_case_dir.path()).expect("loads"))
.collect::<Vec<_>>();
let results = Cases { test_cases }.test_results();
crate::doc::assert_tests_pass(&handler_path, &results);
}
}
macro_rules! bls_handler {
($runner_name: ident, $case_name:ident, $handler_name:expr) => {
pub struct $runner_name;
impl Handler for $runner_name {
type Case = cases::$case_name;
fn runner_name() -> &'static str {
"bls"
}
fn handler_name() -> &'static str {
$handler_name
}
}
};
}
bls_handler!(
BlsAggregatePubkeysHandler,
BlsAggregatePubkeys,
"aggregate_pubkeys"
);
bls_handler!(BlsAggregateSigsHandler, BlsAggregateSigs, "aggregate_sigs");
bls_handler!(
BlsG2CompressedHandler,
BlsG2Compressed,
"msg_hash_compressed"
);
bls_handler!(BlsPrivToPubHandler, BlsPrivToPub, "priv_to_pub");
bls_handler!(BlsSignMsgHandler, BlsSign, "sign_msg");
/// Handler for SSZ types that do not implement `SignedRoot`.
pub struct SszStaticHandler<T, E>(PhantomData<(T, E)>);
/// Handler for SSZ types that do implement `SignedRoot`.
pub struct SszStaticSRHandler<T, E>(PhantomData<(T, E)>);
impl<T, E> Handler for SszStaticHandler<T, E>
where
T: cases::SszStaticType + TypeName,
E: TypeName,
{
type Case = cases::SszStatic<T>;
fn config_name() -> &'static str {
E::name()
}
fn runner_name() -> &'static str {
"ssz_static"
}
fn handler_name() -> &'static str {
T::name()
}
}
impl<T, E> Handler for SszStaticSRHandler<T, E>
where
T: cases::SszStaticType + SignedRoot + TypeName,
E: TypeName,
{
type Case = cases::SszStaticSR<T>;
fn config_name() -> &'static str {
E::name()
}
fn runner_name() -> &'static str {
"ssz_static"
}
fn handler_name() -> &'static str {
T::name()
}
}

View File

@ -4,6 +4,7 @@ pub use case_result::CaseResult;
pub use cases::Case;
pub use doc::Doc;
pub use error::Error;
pub use handler::*;
pub use yaml_decode::YamlDecode;
mod bls_setting;
@ -12,6 +13,8 @@ mod cases;
mod doc;
mod doc_header;
mod error;
mod handler;
mod type_name;
mod yaml_decode;
/// Defined where an object can return the results of some test(s) adhering to the Ethereum

View File

@ -0,0 +1,61 @@
//! Mapping from types to canonical string identifiers used in testing.
use types::*;
pub trait TypeName {
fn name() -> &'static str;
}
impl TypeName for MinimalEthSpec {
fn name() -> &'static str {
"minimal"
}
}
impl TypeName for MainnetEthSpec {
fn name() -> &'static str {
"mainnet"
}
}
macro_rules! impl_name {
($typ:ident) => {
impl TypeName for $typ {
fn name() -> &'static str {
stringify!($typ)
}
}
};
}
macro_rules! impl_name_generic {
($typ:ident) => {
impl<E: EthSpec> TypeName for $typ<E> {
fn name() -> &'static str {
stringify!($typ)
}
}
};
}
impl_name_generic!(Attestation);
impl_name!(AttestationData);
impl_name!(AttestationDataAndCustodyBit);
impl_name_generic!(AttesterSlashing);
impl_name_generic!(BeaconBlock);
impl_name_generic!(BeaconBlockBody);
impl_name!(BeaconBlockHeader);
impl_name_generic!(BeaconState);
impl_name!(Checkpoint);
impl_name_generic!(CompactCommittee);
impl_name!(Crosslink);
impl_name!(Deposit);
impl_name!(DepositData);
impl_name!(Eth1Data);
impl_name!(Fork);
impl_name_generic!(HistoricalBatch);
impl_name_generic!(IndexedAttestation);
impl_name_generic!(PendingAttestation);
impl_name!(ProposerSlashing);
impl_name!(Transfer);
impl_name!(Validator);
impl_name!(VoluntaryExit);

View File

@ -1,14 +1,20 @@
use super::*;
use ethereum_types::{U128, U256};
use std::fs;
use std::path::Path;
use types::Fork;
mod utils;
pub use utils::*;
pub trait YamlDecode: Sized {
/// Decode an object from the test specification YAML.
fn yaml_decode(string: &str) -> Result<Self, Error>;
fn yaml_decode_file(path: &Path) -> Result<Self, Error> {
fs::read_to_string(path)
.map_err(|e| {
Error::FailedToParseTest(format!("Unable to load {}: {:?}", path.display(), e))
})
.and_then(|s| Self::yaml_decode(&s))
}
}
/// Basic types can general be decoded with the `parse` fn if they implement `str::FromStr`.

View File

@ -1,10 +0,0 @@
pub fn yaml_split_header_and_cases(mut yaml: String) -> (String, String) {
let test_cases_start = yaml.find("\ntest_cases:\n").unwrap();
// + 1 to skip the \n we used for matching.
let mut test_cases = yaml.split_off(test_cases_start + 1);
let end_of_first_line = test_cases.find('\n').unwrap();
let test_cases = test_cases.split_off(end_of_first_line + 1);
(yaml, test_cases)
}

View File

@ -1,12 +1,20 @@
use ef_tests::*;
use rayon::prelude::*;
use std::path::{Path, PathBuf};
use types::{
Attestation, AttestationData, AttestationDataAndCustodyBit, AttesterSlashing, BeaconBlock,
BeaconBlockBody, BeaconBlockHeader, BeaconState, Checkpoint, CompactCommittee, Crosslink,
Deposit, DepositData, Eth1Data, Fork, HistoricalBatch, IndexedAttestation, MainnetEthSpec,
MinimalEthSpec, PendingAttestation, ProposerSlashing, Transfer, Validator, VoluntaryExit,
};
use walkdir::WalkDir;
fn yaml_files_in_test_dir(dir: &Path) -> Vec<PathBuf> {
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("eth2.0-spec-tests")
.join("tests")
.join("general")
.join("phase0")
.join(dir);
assert!(
@ -155,12 +163,107 @@ fn sanity_slots() {
#[cfg(not(feature = "fake_crypto"))]
fn bls() {
yaml_files_in_test_dir(&Path::new("bls"))
.into_par_iter()
.into_iter()
.for_each(|file| {
Doc::assert_tests_pass(file);
});
}
#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls_aggregate_pubkeys() {
BlsAggregatePubkeysHandler::run();
}
#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls_aggregate_sigs() {
BlsAggregateSigsHandler::run();
}
#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls_msg_hash_g2_compressed() {
BlsG2CompressedHandler::run();
}
#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls_priv_to_pub() {
BlsPrivToPubHandler::run();
}
#[test]
#[cfg(not(feature = "fake_crypto"))]
fn bls_sign_msg() {
BlsSignMsgHandler::run();
}
macro_rules! ssz_static_test {
// Signed-root
($test_name:ident, $typ:ident$(<$generics:tt>)?, SR) => {
ssz_static_test!($test_name, SszStaticSRHandler, $typ$(<$generics>)?);
};
// Non-signed root
($test_name:ident, $typ:ident$(<$generics:tt>)?) => {
ssz_static_test!($test_name, SszStaticHandler, $typ$(<$generics>)?);
};
// Generic
($test_name:ident, $handler:ident, $typ:ident<_>) => {
ssz_static_test!(
$test_name, $handler, {
($typ<MinimalEthSpec>, MinimalEthSpec),
($typ<MainnetEthSpec>, MainnetEthSpec)
}
);
};
// Non-generic
($test_name:ident, $handler:ident, $typ:ident) => {
ssz_static_test!(
$test_name, $handler, {
($typ, MinimalEthSpec),
($typ, MainnetEthSpec)
}
);
};
// Base case
($test_name:ident, $handler:ident, { $(($typ:ty, $spec:ident)),+ }) => {
#[test]
#[cfg(feature = "fake_crypto")]
fn $test_name() {
$(
$handler::<$typ, $spec>::run();
)+
}
};
}
ssz_static_test!(ssz_static_attestation, Attestation<_>, SR);
ssz_static_test!(ssz_static_attestation_data, AttestationData);
ssz_static_test!(
ssz_static_attestation_data_and_custody_bit,
AttestationDataAndCustodyBit
);
ssz_static_test!(ssz_static_attester_slashing, AttesterSlashing<_>);
ssz_static_test!(ssz_static_beacon_block, BeaconBlock<_>, SR);
ssz_static_test!(ssz_static_beacon_block_body, BeaconBlockBody<_>);
ssz_static_test!(ssz_static_beacon_block_header, BeaconBlockHeader, SR);
ssz_static_test!(ssz_static_beacon_state, BeaconState<_>);
ssz_static_test!(ssz_static_checkpoint, Checkpoint);
ssz_static_test!(ssz_static_compact_committee, CompactCommittee<_>);
ssz_static_test!(ssz_static_crosslink, Crosslink);
ssz_static_test!(ssz_static_deposit, Deposit);
ssz_static_test!(ssz_static_deposit_data, DepositData, SR);
ssz_static_test!(ssz_static_eth1_data, Eth1Data);
ssz_static_test!(ssz_static_fork, Fork);
ssz_static_test!(ssz_static_historical_batch, HistoricalBatch<_>);
ssz_static_test!(ssz_static_indexed_attestation, IndexedAttestation<_>, SR);
ssz_static_test!(ssz_static_pending_attestation, PendingAttestation<_>);
ssz_static_test!(ssz_static_proposer_slashing, ProposerSlashing);
ssz_static_test!(ssz_static_transfer, Transfer, SR);
ssz_static_test!(ssz_static_validator, Validator);
ssz_static_test!(ssz_static_voluntary_exit, VoluntaryExit, SR);
#[test]
fn epoch_processing_justification_and_finalization() {
yaml_files_in_test_dir(&Path::new("epoch_processing").join("justification_and_finalization"))