Operations tests

This commit is contained in:
Michael Sproul
2019-08-30 16:16:38 +10:00
parent c5a22b57d2
commit fcf16faad3
11 changed files with 248 additions and 405 deletions

View File

@@ -0,0 +1,193 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use crate::type_name::TypeName;
use crate::yaml_decode::{ssz_decode_file, yaml_decode_file};
use serde_derive::Deserialize;
use ssz::Decode;
use state_processing::per_block_processing::{
errors::BlockProcessingError, process_attestations, process_attester_slashings,
process_block_header, process_deposits, process_exits, process_proposer_slashings,
process_transfers,
};
use std::path::{Path, PathBuf};
use types::{
Attestation, AttesterSlashing, BeaconBlock, BeaconState, ChainSpec, Deposit, EthSpec,
ProposerSlashing, Transfer, VoluntaryExit,
};
#[derive(Debug, Clone, Default, Deserialize)]
struct Metadata {
description: Option<String>,
bls_setting: Option<BlsSetting>,
}
#[derive(Debug, Clone)]
pub struct Operations<E: EthSpec, O: Operation<E>> {
pub path: PathBuf,
metadata: Metadata,
pub pre: BeaconState<E>,
pub operation: O,
pub post: Option<BeaconState<E>>,
}
pub trait Operation<E: EthSpec>: Decode + TypeName + std::fmt::Debug {
fn handler_name() -> String {
Self::name().to_lowercase()
}
fn filename() -> String {
format!("{}.ssz", Self::handler_name())
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError>;
}
impl<E: EthSpec> Operation<E> for Attestation<E> {
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_attestations(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for AttesterSlashing<E> {
fn handler_name() -> String {
"attester_slashing".into()
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_attester_slashings(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for Deposit {
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_deposits(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for ProposerSlashing {
fn handler_name() -> String {
"proposer_slashing".into()
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_proposer_slashings(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for Transfer {
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_transfers(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for VoluntaryExit {
fn handler_name() -> String {
"voluntary_exit".into()
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_exits(state, &[self.clone()], spec)
}
}
impl<E: EthSpec> Operation<E> for BeaconBlock<E> {
fn handler_name() -> String {
"block_header".into()
}
fn filename() -> String {
"block.ssz".into()
}
fn apply_to(
&self,
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
process_block_header(state, self, spec, true)
}
}
impl<E: EthSpec, O: Operation<E>> LoadCase for Operations<E, O> {
fn load_from_dir(path: &Path) -> Result<Self, Error> {
let metadata_path = path.join("meta.yaml");
let metadata: Metadata = if metadata_path.is_file() {
yaml_decode_file(&metadata_path)?
} else {
Metadata::default()
};
let pre = ssz_decode_file(&path.join("pre.ssz"))?;
let operation = ssz_decode_file(&path.join(O::filename()))?;
let post_filename = path.join("post.ssz");
let post = if post_filename.is_file() {
Some(ssz_decode_file(&post_filename)?)
} else {
None
};
Ok(Self {
path: path.into(),
metadata,
pre,
operation,
post,
})
}
}
impl<E: EthSpec, O: Operation<E>> Case for Operations<E, O> {
fn description(&self) -> String {
self.metadata
.description
.clone()
.unwrap_or_else(String::new)
}
fn path(&self) -> &Path {
&self.path
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.metadata.bls_setting.unwrap_or_default().check()?;
let spec = &E::default_spec();
let mut state = self.pre.clone();
let mut expected = self.post.clone();
// Processing requires the epoch cache.
state.build_all_caches(spec).unwrap();
let mut result = self.operation.apply_to(&mut state, spec).map(|()| state);
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,47 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_attestations;
use types::{Attestation, BeaconState, EthSpec};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsAttestation<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub attestation: Attestation<E>,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsAttestation<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(&yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsAttestation<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
let spec = &E::default_spec();
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let attestation = self.attestation.clone();
let mut expected = self.post.clone();
// Processing requires the epoch cache.
state.build_all_caches(spec).unwrap();
let result = process_attestations(&mut state, &[attestation], spec);
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,48 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_attester_slashings;
use types::{AttesterSlashing, BeaconState, EthSpec};
#[derive(Debug, Clone, Deserialize)]
pub struct OperationsAttesterSlashing<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
#[serde(bound = "E: EthSpec")]
pub pre: BeaconState<E>,
#[serde(bound = "E: EthSpec")]
pub attester_slashing: AttesterSlashing<E>,
#[serde(bound = "E: EthSpec")]
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsAttesterSlashing<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsAttesterSlashing<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let attester_slashing = self.attester_slashing.clone();
let mut expected = self.post.clone();
// Processing requires the epoch cache.
state.build_all_caches(&E::default_spec()).unwrap();
let result =
process_attester_slashings(&mut state, &[attester_slashing], &E::default_spec());
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,44 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_block_header;
use types::{BeaconBlock, BeaconState, EthSpec};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsBlockHeader<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub block: BeaconBlock<E>,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsBlockHeader<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsBlockHeader<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
let spec = &E::default_spec();
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let mut expected = self.post.clone();
// Processing requires the epoch cache.
state.build_all_caches(spec).unwrap();
let mut result = process_block_header(&mut state, &self.block, spec, true).map(|_| state);
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,42 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_deposits;
use types::{BeaconState, Deposit, EthSpec};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsDeposit<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub deposit: Deposit,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsDeposit<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsDeposit<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let deposit = self.deposit.clone();
let mut expected = self.post.clone();
let result = process_deposits(&mut state, &[deposit], &E::default_spec());
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,45 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_exits;
use types::{BeaconState, EthSpec, VoluntaryExit};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsExit<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub voluntary_exit: VoluntaryExit,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsExit<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsExit<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let exit = self.voluntary_exit.clone();
let mut expected = self.post.clone();
// Exit processing requires the epoch cache.
state.build_all_caches(&E::default_spec()).unwrap();
let result = process_exits(&mut state, &[exit], &E::default_spec());
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,46 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_proposer_slashings;
use types::{BeaconState, EthSpec, ProposerSlashing};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsProposerSlashing<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub proposer_slashing: ProposerSlashing,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsProposerSlashing<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsProposerSlashing<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let proposer_slashing = self.proposer_slashing.clone();
let mut expected = self.post.clone();
// Processing requires the epoch cache.
state.build_all_caches(&E::default_spec()).unwrap();
let result =
process_proposer_slashings(&mut state, &[proposer_slashing], &E::default_spec());
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}

View File

@@ -1,47 +0,0 @@
use super::*;
use crate::bls_setting::BlsSetting;
use crate::case_result::compare_beacon_state_results_without_caches;
use serde_derive::Deserialize;
use state_processing::per_block_processing::process_transfers;
use types::{BeaconState, EthSpec, Transfer};
#[derive(Debug, Clone, Deserialize)]
#[serde(bound = "E: EthSpec")]
pub struct OperationsTransfer<E: EthSpec> {
pub description: String,
pub bls_setting: Option<BlsSetting>,
pub pre: BeaconState<E>,
pub transfer: Transfer,
pub post: Option<BeaconState<E>>,
}
impl<E: EthSpec> YamlDecode for OperationsTransfer<E> {
fn yaml_decode(yaml: &str) -> Result<Self, Error> {
Ok(serde_yaml::from_str(yaml).unwrap())
}
}
impl<E: EthSpec> Case for OperationsTransfer<E> {
fn description(&self) -> String {
self.description.clone()
}
fn result(&self, _case_index: usize) -> Result<(), Error> {
self.bls_setting.unwrap_or_default().check()?;
let mut state = self.pre.clone();
let transfer = self.transfer.clone();
let mut expected = self.post.clone();
// Transfer processing requires the epoch cache.
state.build_all_caches(&E::default_spec()).unwrap();
let spec = E::default_spec();
let result = process_transfers(&mut state, &[transfer], &spec);
let mut result = result.and_then(|_| Ok(state));
compare_beacon_state_results_without_caches(&mut result, &mut expected)
}
}