diff --git a/README.md b/README.md index 39426fe97..7e66dc519 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Like all Ethereum 2.0 clients, Lighthouse is a work-in-progress. Current development overview: -- Specification `v0.12.1` implemented, optimized and passing test vectors. +- Specification `v0.12.3` implemented, optimized and passing test vectors. - Rust-native libp2p with Gossipsub and Discv5. - RESTful JSON API via HTTP server. - Events via WebSocket. diff --git a/consensus/state_processing/src/per_epoch_processing/process_slashings.rs b/consensus/state_processing/src/per_epoch_processing/process_slashings.rs index 4a8f8120d..40d96f30c 100644 --- a/consensus/state_processing/src/per_epoch_processing/process_slashings.rs +++ b/consensus/state_processing/src/per_epoch_processing/process_slashings.rs @@ -11,6 +11,10 @@ pub fn process_slashings( ) -> Result<(), Error> { let epoch = state.current_epoch(); let sum_slashings = state.get_all_slashings().iter().copied().safe_sum()?; + let adjusted_total_slashing_balance = std::cmp::min( + sum_slashings.safe_mul(spec.proportional_slashing_multiplier)?, + total_balance, + ); for (index, validator) in state.validators.iter().enumerate() { if validator.slashed @@ -21,7 +25,7 @@ pub fn process_slashings( let penalty_numerator = validator .effective_balance .safe_div(increment)? - .safe_mul(std::cmp::min(sum_slashings.safe_mul(3)?, total_balance))?; + .safe_mul(adjusted_total_slashing_balance)?; let penalty = penalty_numerator .safe_div(total_balance)? .safe_mul(increment)?; diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 5afe7db8f..c621acb81 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -52,6 +52,7 @@ pub struct ChainSpec { pub hysteresis_quotient: u64, pub hysteresis_downward_multiplier: u64, pub hysteresis_upward_multiplier: u64, + pub proportional_slashing_multiplier: u64, /* * Gwei values @@ -243,7 +244,7 @@ impl ChainSpec { /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification. /// - /// Spec v0.12.1 + /// Spec v0.12.3 pub fn mainnet() -> Self { Self { /* @@ -267,6 +268,7 @@ impl ChainSpec { hysteresis_quotient: 4, hysteresis_downward_multiplier: 1, hysteresis_upward_multiplier: 5, + proportional_slashing_multiplier: 3, /* * Gwei values @@ -437,21 +439,15 @@ mod tests { } } -/// Union of a ChainSpec struct and an EthSpec struct that holds constants used for the configs -/// from the Ethereum 2 specs repo (https://github.com/ethereum/eth2.0-specs/tree/dev/configs) +/// YAML config file as defined by the spec. /// -/// Doesn't include fields of the YAML that we don't need yet (e.g. Phase 1 stuff). -/// -/// Spec v0.12.1 -// Yaml Config is declared here in order to access domain fields of ChainSpec which are private. +/// Spec v0.12.3 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(rename_all = "UPPERCASE")] -#[serde(default)] pub struct YamlConfig { + #[serde(default)] + config_name: String, // ChainSpec - far_future_epoch: u64, - base_rewards_per_epoch: u64, - deposit_contract_tree_depth: u64, max_committees_per_slot: usize, target_committee_size: usize, min_per_epoch_churn_limit: u64, @@ -467,7 +463,9 @@ pub struct YamlConfig { hysteresis_quotient: u64, hysteresis_downward_multiplier: u64, hysteresis_upward_multiplier: u64, - genesis_slot: u64, + // Proportional slashing multiplier defaults to 3 for compatibility with Altona and Medalla. + #[serde(default = "default_proportional_slashing_multiplier")] + proportional_slashing_multiplier: u64, #[serde( serialize_with = "fork_to_hex_str", deserialize_with = "fork_from_hex_str" @@ -524,14 +522,8 @@ pub struct YamlConfig { serialize_with = "u32_to_hex_str" )] domain_aggregate_and_proof: u32, - #[serde( - deserialize_with = "u32_from_hex_str", - serialize_with = "u32_to_hex_str" - )] // EthSpec - justification_bits_length: u32, max_validators_per_committee: u32, - genesis_epoch: Epoch, slots_per_epoch: u64, epochs_per_eth1_voting_period: u64, slots_per_historical_root: usize, @@ -544,13 +536,22 @@ pub struct YamlConfig { max_attestations: u32, max_deposits: u32, max_voluntary_exits: u32, - // Validator eth1_follow_distance: u64, target_aggregators_per_committee: u64, random_subnets_per_validator: u64, epochs_per_random_subnet_subscription: u64, seconds_per_eth1_block: u64, + /* TODO: incorporate these into ChainSpec and turn on `serde(deny_unknown_fields)` + deposit_chain_id: u64, + deposit_network_id: u64, + deposit_contract_address: String, + */ +} + +// Compatibility shim for proportional slashing multpilier on Altona and Medalla. +fn default_proportional_slashing_multiplier() -> u64 { + 3 } impl Default for YamlConfig { @@ -565,10 +566,8 @@ impl YamlConfig { #[allow(clippy::integer_arithmetic)] pub fn from_spec(spec: &ChainSpec) -> Self { Self { + config_name: T::spec_name().to_string(), // ChainSpec - far_future_epoch: spec.far_future_epoch.into(), - base_rewards_per_epoch: spec.base_rewards_per_epoch, - deposit_contract_tree_depth: spec.deposit_contract_tree_depth, max_committees_per_slot: spec.max_committees_per_slot, target_committee_size: spec.target_committee_size, min_per_epoch_churn_limit: spec.min_per_epoch_churn_limit, @@ -584,7 +583,7 @@ impl YamlConfig { hysteresis_quotient: spec.hysteresis_quotient, hysteresis_downward_multiplier: spec.hysteresis_downward_multiplier, hysteresis_upward_multiplier: spec.hysteresis_upward_multiplier, - genesis_slot: spec.genesis_slot.into(), + proportional_slashing_multiplier: spec.proportional_slashing_multiplier, bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte, seconds_per_slot: spec.milliseconds_per_slot / 1000, min_attestation_inclusion_delay: spec.min_attestation_inclusion_delay, @@ -609,9 +608,7 @@ impl YamlConfig { domain_aggregate_and_proof: spec.domain_aggregate_and_proof, // EthSpec - justification_bits_length: T::JustificationBitsLength::to_u32(), max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u32(), - genesis_epoch: T::genesis_epoch(), slots_per_epoch: T::slots_per_epoch(), epochs_per_eth1_voting_period: T::EpochsPerEth1VotingPeriod::to_u64(), slots_per_historical_root: T::slots_per_historical_root(), @@ -642,10 +639,8 @@ impl YamlConfig { } pub fn apply_to_chain_spec(&self, chain_spec: &ChainSpec) -> Option { - // Checking for EthSpec constants - if self.justification_bits_length != T::JustificationBitsLength::to_u32() - || self.max_validators_per_committee != T::MaxValidatorsPerCommittee::to_u32() - || self.genesis_epoch != T::genesis_epoch() + // Check that YAML values match type-level EthSpec constants + if self.max_validators_per_committee != T::MaxValidatorsPerCommittee::to_u32() || self.slots_per_epoch != T::slots_per_epoch() || self.epochs_per_eth1_voting_period != T::EpochsPerEth1VotingPeriod::to_u64() || self.slots_per_historical_root != T::slots_per_historical_root() @@ -664,25 +659,48 @@ impl YamlConfig { // Create a ChainSpec from the yaml config Some(ChainSpec { - far_future_epoch: Epoch::from(self.far_future_epoch), - base_rewards_per_epoch: self.base_rewards_per_epoch, - deposit_contract_tree_depth: self.deposit_contract_tree_depth, + /* + * Misc + */ + max_committees_per_slot: self.max_committees_per_slot, target_committee_size: self.target_committee_size, min_per_epoch_churn_limit: self.min_per_epoch_churn_limit, churn_limit_quotient: self.churn_limit_quotient, shuffle_round_count: self.shuffle_round_count, min_genesis_active_validator_count: self.min_genesis_active_validator_count, min_genesis_time: self.min_genesis_time, - min_deposit_amount: self.min_deposit_amount, - genesis_delay: self.genesis_delay, - max_effective_balance: self.max_effective_balance, hysteresis_quotient: self.hysteresis_quotient, hysteresis_downward_multiplier: self.hysteresis_downward_multiplier, hysteresis_upward_multiplier: self.hysteresis_upward_multiplier, + proportional_slashing_multiplier: self.proportional_slashing_multiplier, + /* + * Fork Choice + */ + safe_slots_to_update_justified: self.safe_slots_to_update_justified, + /* + * Validator + */ + eth1_follow_distance: self.eth1_follow_distance, + target_aggregators_per_committee: self.target_aggregators_per_committee, + random_subnets_per_validator: self.random_subnets_per_validator, + epochs_per_random_subnet_subscription: self.epochs_per_random_subnet_subscription, + seconds_per_eth1_block: self.seconds_per_eth1_block, + /* + * Gwei values + */ + min_deposit_amount: self.min_deposit_amount, + max_effective_balance: self.max_effective_balance, ejection_balance: self.ejection_balance, effective_balance_increment: self.effective_balance_increment, - genesis_slot: Slot::from(self.genesis_slot), + /* + * Initial values + */ + genesis_fork_version: self.genesis_fork_version, bls_withdrawal_prefix_byte: self.bls_withdrawal_prefix, + /* + * Time parameters + */ + genesis_delay: self.genesis_delay, milliseconds_per_slot: self.seconds_per_slot.saturating_mul(1000), min_attestation_inclusion_delay: self.min_attestation_inclusion_delay, min_seed_lookahead: Epoch::from(self.min_seed_lookahead), @@ -692,20 +710,43 @@ impl YamlConfig { ), shard_committee_period: self.shard_committee_period, min_epochs_to_inactivity_penalty: self.min_epochs_to_inactivity_penalty, + /* + * Reward and penalty quotients + */ base_reward_factor: self.base_reward_factor, whistleblower_reward_quotient: self.whistleblower_reward_quotient, proposer_reward_quotient: self.proposer_reward_quotient, inactivity_penalty_quotient: self.inactivity_penalty_quotient, min_slashing_penalty_quotient: self.min_slashing_penalty_quotient, + /* + * Signature domains + */ domain_beacon_proposer: self.domain_beacon_proposer, domain_beacon_attester: self.domain_beacon_attester, domain_randao: self.domain_randao, domain_deposit: self.domain_deposit, domain_voluntary_exit: self.domain_voluntary_exit, + domain_selection_proof: self.domain_selection_proof, + domain_aggregate_and_proof: self.domain_aggregate_and_proof, + /* + * Lighthouse-specific parameters + * + * These are paramaters that are present in the chain spec but aren't part of the YAML + * config. We avoid using `..chain_spec` so that changes to the set of fields don't + * accidentally get forgotten (explicit better than implicit, yada yada). + */ boot_nodes: chain_spec.boot_nodes.clone(), - genesis_fork_version: self.genesis_fork_version, - eth1_follow_distance: self.eth1_follow_distance, - ..*chain_spec + network_id: chain_spec.network_id, + attestation_propagation_slot_range: chain_spec.attestation_propagation_slot_range, + maximum_gossip_clock_disparity_millis: chain_spec.maximum_gossip_clock_disparity_millis, + attestation_subnet_count: chain_spec.attestation_subnet_count, + /* + * Constants, not configurable. + */ + genesis_slot: chain_spec.genesis_slot, + far_future_epoch: chain_spec.far_future_epoch, + base_rewards_per_epoch: chain_spec.base_rewards_per_epoch, + deposit_contract_tree_depth: chain_spec.deposit_contract_tree_depth, }) } } @@ -768,7 +809,7 @@ mod yaml_tests { let yamlconfig = YamlConfig::from_spec::(&spec); // modifying the original spec - spec.deposit_contract_tree_depth += 1; + spec.max_committees_per_slot += 1; // Applying a yaml config with incorrect EthSpec should fail let res = yamlconfig.apply_to_chain_spec::(&spec); assert_eq!(res, None); diff --git a/lighthouse/environment/tests/environment_builder.rs b/lighthouse/environment/tests/environment_builder.rs index 505f1e632..8594825a5 100644 --- a/lighthouse/environment/tests/environment_builder.rs +++ b/lighthouse/environment/tests/environment_builder.rs @@ -3,7 +3,7 @@ use environment::EnvironmentBuilder; use eth2_testnet_config::Eth2TestnetConfig; use std::path::PathBuf; -use types::{Epoch, MainnetEthSpec, YamlConfig}; +use types::{MainnetEthSpec, YamlConfig}; fn builder() -> EnvironmentBuilder { EnvironmentBuilder::mainnet() @@ -36,8 +36,8 @@ mod setup_eth2_config { .expect("should build environment"); assert_eq!( - environment.eth2_config.spec.far_future_epoch, - Epoch::new(999) // see testnet_dir/config.yaml + environment.eth2_config.spec.max_committees_per_slot, + 128 // see testnet_dir/config.yaml ); } } diff --git a/lighthouse/environment/tests/testnet_dir/config.yaml b/lighthouse/environment/tests/testnet_dir/config.yaml index 7404c99ff..493827f29 100644 --- a/lighthouse/environment/tests/testnet_dir/config.yaml +++ b/lighthouse/environment/tests/testnet_dir/config.yaml @@ -1,56 +1,156 @@ -FAR_FUTURE_EPOCH: 999 # for testing -BASE_REWARDS_PER_EPOCH: 4 -DEPOSIT_CONTRACT_TREE_DEPTH: 32 -MAX_COMMITTEES_PER_SLOT: 64 +# Mainnet preset +# Note: the intention of this file (for now) is to illustrate what a mainnet configuration could look like. +# Some of these constants may still change before the launch of Phase 0. + +CONFIG_NAME: "mainnet" + +# Misc +# --------------------------------------------------------------- +MAX_COMMITTEES_PER_SLOT: 128 # MODIFIED FOR TESTING +# 2**7 (= 128) TARGET_COMMITTEE_SIZE: 128 +# 2**11 (= 2,048) +MAX_VALIDATORS_PER_COMMITTEE: 2048 +# 2**2 (= 4) MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536 +# See issue 563 SHUFFLE_ROUND_COUNT: 90 -MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 4096 -MIN_GENESIS_TIME: 0 -GENESIS_DELAY: 3600 -MIN_DEPOSIT_AMOUNT: 10000000 -MAX_EFFECTIVE_BALANCE: 3200000000 -EJECTION_BALANCE: 1600000000 -EFFECTIVE_BALANCE_INCREMENT: 100000000 -GENESIS_SLOT: 0 -GENESIS_FORK_VERSION: 0x01030307 -BLS_WITHDRAWAL_PREFIX: 0x00 -SECONDS_PER_SLOT: 12 -MIN_ATTESTATION_INCLUSION_DELAY: 1 -MIN_SEED_LOOKAHEAD: 1 -MAX_SEED_LOOKAHEAD: 4 -MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 -MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 -PERSISTENT_COMMITTEE_PERIOD: 2048 -BASE_REWARD_FACTOR: 64 -WHISTLEBLOWER_REWARD_QUOTIENT: 512 -PROPOSER_REWARD_QUOTIENT: 8 -INACTIVITY_PENALTY_QUOTIENT: 33554432 -MIN_SLASHING_PENALTY_QUOTIENT: 32 +# `2**14` (= 16,384) +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 +# Jan 3, 2020 +MIN_GENESIS_TIME: 1578009600 +# 4 +HYSTERESIS_QUOTIENT: 4 +# 1 (minus 0.25) +HYSTERESIS_DOWNWARD_MULTIPLIER: 1 +# 5 (plus 1.25) +HYSTERESIS_UPWARD_MULTIPLIER: 5 +# 3 +PROPORTIONAL_SLASHING_MULTIPLIER: 3 + + +# Fork Choice +# --------------------------------------------------------------- +# 2**3 (= 8) SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8 + + +# Validator +# --------------------------------------------------------------- +# 2**10 (= 1,024) +ETH1_FOLLOW_DISTANCE: 1024 +# 2**4 (= 16) +TARGET_AGGREGATORS_PER_COMMITTEE: 16 +# 2**0 (= 1) +RANDOM_SUBNETS_PER_VALIDATOR: 1 +# 2**8 (= 256) +EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 + + +# Deposit contract +# --------------------------------------------------------------- +# Ethereum PoW Mainnet +DEPOSIT_CHAIN_ID: 1 +DEPOSIT_NETWORK_ID: 1 +# **TBD** +DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 + + +# Gwei values +# --------------------------------------------------------------- +# 2**0 * 10**9 (= 1,000,000,000) Gwei +MIN_DEPOSIT_AMOUNT: 1000000000 +# 2**5 * 10**9 (= 32,000,000,000) Gwei +MAX_EFFECTIVE_BALANCE: 32000000000 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**0 * 10**9 (= 1,000,000,000) Gwei +EFFECTIVE_BALANCE_INCREMENT: 1000000000 + + +# Initial values +# --------------------------------------------------------------- +# Mainnet initial fork version, recommend altering for testnets +GENESIS_FORK_VERSION: 0x00000000 +BLS_WITHDRAWAL_PREFIX: 0x00 + + +# Time parameters +# --------------------------------------------------------------- +# 172800 seconds (2 days) +GENESIS_DELAY: 172800 +# 12 seconds +SECONDS_PER_SLOT: 12 +# 2**0 (= 1) slots 12 seconds +MIN_ATTESTATION_INCLUSION_DELAY: 1 +# 2**5 (= 32) slots 6.4 minutes +SLOTS_PER_EPOCH: 32 +# 2**0 (= 1) epochs 6.4 minutes +MIN_SEED_LOOKAHEAD: 1 +# 2**2 (= 4) epochs 25.6 minutes +MAX_SEED_LOOKAHEAD: 4 +# 2**5 (= 32) epochs ~3.4 hours +EPOCHS_PER_ETH1_VOTING_PERIOD: 32 +# 2**13 (= 8,192) slots ~13 hours +SLOTS_PER_HISTORICAL_ROOT: 8192 +# 2**8 (= 256) epochs ~27 hours +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 +# 2**8 (= 256) epochs ~27 hours +SHARD_COMMITTEE_PERIOD: 256 +# 2**2 (= 4) epochs 25.6 minutes +MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 + + +# State vector lengths +# --------------------------------------------------------------- +# 2**16 (= 65,536) epochs ~0.8 years +EPOCHS_PER_HISTORICAL_VECTOR: 65536 +# 2**13 (= 8,192) epochs ~36 days +EPOCHS_PER_SLASHINGS_VECTOR: 8192 +# 2**24 (= 16,777,216) historical roots, ~26,131 years +HISTORICAL_ROOTS_LIMIT: 16777216 +# 2**40 (= 1,099,511,627,776) validator spots +VALIDATOR_REGISTRY_LIMIT: 1099511627776 + + +# Reward and penalty quotients +# --------------------------------------------------------------- +# 2**6 (= 64) +BASE_REWARD_FACTOR: 64 +# 2**9 (= 512) +WHISTLEBLOWER_REWARD_QUOTIENT: 512 +# 2**3 (= 8) +PROPOSER_REWARD_QUOTIENT: 8 +# 2**24 (= 16,777,216) +INACTIVITY_PENALTY_QUOTIENT: 16777216 +# 2**5 (= 32) +MIN_SLASHING_PENALTY_QUOTIENT: 32 + + +# Max operations per block +# --------------------------------------------------------------- +# 2**4 (= 16) +MAX_PROPOSER_SLASHINGS: 16 +# 2**1 (= 2) +MAX_ATTESTER_SLASHINGS: 2 +# 2**7 (= 128) +MAX_ATTESTATIONS: 128 +# 2**4 (= 16) +MAX_DEPOSITS: 16 +# 2**4 (= 16) +MAX_VOLUNTARY_EXITS: 16 + + +# Signature domains +# --------------------------------------------------------------- DOMAIN_BEACON_PROPOSER: 0x00000000 DOMAIN_BEACON_ATTESTER: 0x01000000 DOMAIN_RANDAO: 0x02000000 DOMAIN_DEPOSIT: 0x03000000 DOMAIN_VOLUNTARY_EXIT: 0x04000000 -JUSTIFICATION_BITS_LENGTH: 0x04000000 -MAX_VALIDATORS_PER_COMMITTEE: 2048 -GENESIS_EPOCH: 0 -SLOTS_PER_EPOCH: 32 -SLOTS_PER_ETH1_VOTING_PERIOD: 1024 -SLOTS_PER_HISTORICAL_ROOT: 8192 -EPOCHS_PER_HISTORICAL_VECTOR: 65536 -EPOCHS_PER_SLASHINGS_VECTOR: 8192 -HISTORICAL_ROOTS_LIMIT: 16777216 -VALIDATOR_REGISTRY_LIMIT: 1099511627776 -MAX_PROPOSER_SLASHINGS: 16 -MAX_ATTESTER_SLASHINGS: 2 -MAX_ATTESTATIONS: 128 -MAX_DEPOSITS: 16 -MAX_VOLUNTARY_EXITS: 16 -ETH1_FOLLOW_DISTANCE: 16 -TARGET_AGGREGATORS_PER_COMMITTEE: 0 -RANDOM_SUBNETS_PER_VALIDATOR: 0 -EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 0 -SECONDS_PER_ETH1_BLOCK: 14 +DOMAIN_SELECTION_PROOF: 0x05000000 +DOMAIN_AGGREGATE_AND_PROOF: 0x06000000 diff --git a/testing/ef_tests/Makefile b/testing/ef_tests/Makefile index a8e6c73c0..e9d7275ad 100644 --- a/testing/ef_tests/Makefile +++ b/testing/ef_tests/Makefile @@ -1,4 +1,4 @@ -TESTS_TAG := v0.12.2 +TESTS_TAG := v0.12.3 TESTS = general minimal mainnet TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS)) diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index ff6dad6dd..9f39a46c6 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -140,13 +140,20 @@ impl> LoadCase for Operations { // Check BLS setting here before SSZ deserialization, as most types require signatures // to be valid. - let operation = if metadata.bls_setting.unwrap_or_default().check().is_ok() { - Some(ssz_decode_file(&path.join(O::filename()))?) + let (operation, bls_error) = if metadata.bls_setting.unwrap_or_default().check().is_ok() { + match ssz_decode_file(&path.join(O::filename())) { + Ok(op) => (Some(op), None), + Err(Error::InvalidBLSInput(error)) => (None, Some(error)), + Err(e) => return Err(e), + } } else { - None + (None, None) }; let post_filename = path.join("post.ssz"); let post = if post_filename.is_file() { + if let Some(bls_error) = bls_error { + panic!("input is unexpectedly invalid: {}", bls_error); + } Some(ssz_decode_file(&post_filename)?) } else { None diff --git a/testing/ef_tests/src/decode.rs b/testing/ef_tests/src/decode.rs index c1ea6fb3b..8d6486bb8 100644 --- a/testing/ef_tests/src/decode.rs +++ b/testing/ef_tests/src/decode.rs @@ -21,11 +21,19 @@ pub fn ssz_decode_file(path: &Path) -> Result { }) .and_then(|s| { T::from_ssz_bytes(&s).map_err(|e| { - Error::FailedToParseTest(format!( - "Unable to parse SSZ at {}: {:?}", - path.display(), - e - )) + match e { + // NOTE: this is a bit hacky, but seemingly better than the alternatives + ssz::DecodeError::BytesInvalid(message) + if message.contains("Blst") || message.contains("Milagro") => + { + Error::InvalidBLSInput(message) + } + e => Error::FailedToParseTest(format!( + "Unable to parse SSZ at {}: {:?}", + path.display(), + e + )), + } }) }) } diff --git a/testing/ef_tests/src/error.rs b/testing/ef_tests/src/error.rs index 98ac9e6dd..2adec6dc1 100644 --- a/testing/ef_tests/src/error.rs +++ b/testing/ef_tests/src/error.rs @@ -6,6 +6,8 @@ pub enum Error { DidntFail(String), /// Failed to parse the test (internal error). FailedToParseTest(String), + /// Test case contained invalid BLS data. + InvalidBLSInput(String), /// Skipped the test because the BLS setting was mismatched. SkippedBls, /// Skipped the test because it's known to fail. @@ -18,6 +20,7 @@ impl Error { Error::NotEqual(_) => "NotEqual", Error::DidntFail(_) => "DidntFail", Error::FailedToParseTest(_) => "FailedToParseTest", + Error::InvalidBLSInput(_) => "InvalidBLSInput", Error::SkippedBls => "SkippedBls", Error::SkippedKnownFailure => "SkippedKnownFailure", } @@ -28,6 +31,7 @@ impl Error { Error::NotEqual(m) => m.as_str(), Error::DidntFail(m) => m.as_str(), Error::FailedToParseTest(m) => m.as_str(), + Error::InvalidBLSInput(m) => m.as_str(), _ => self.name(), } }