parent
							
								
									a236003a7b
								
							
						
					
					
						commit
						eb669ab40f
					
				| @ -14,15 +14,22 @@ pub fn get_compact_committees_root<T: EthSpec>( | ||||
|     // FIXME: this is a spec bug, whereby the start shard for the epoch after the next epoch
 | ||||
|     // is mistakenly used. The start shard from the cache SHOULD work.
 | ||||
|     // Waiting on a release to fix https://github.com/ethereum/eth2.0-specs/issues/1315
 | ||||
|     // let start_shard = state.get_epoch_start_shard(relative_epoch)?;
 | ||||
|     let start_shard = state.next_epoch_start_shard(spec)?; | ||||
|     let start_shard = if relative_epoch == RelativeEpoch::Next { | ||||
|         state.next_epoch_start_shard(spec)? | ||||
|     } else { | ||||
|         state.get_epoch_start_shard(relative_epoch)? | ||||
|     }; | ||||
| 
 | ||||
|     for committee_number in 0..state.get_committee_count(relative_epoch)? { | ||||
|         let shard = (start_shard + committee_number) % T::ShardCount::to_u64(); | ||||
|         // FIXME: this is a partial workaround for the above, but it only works in the case
 | ||||
|         // where there's a committee for every shard in every epoch. It works for the minimal
 | ||||
|         // tests but not the mainnet ones.
 | ||||
|         let fake_shard = (shard + 1) % T::ShardCount::to_u64(); | ||||
|         let fake_shard = if relative_epoch == RelativeEpoch::Next { | ||||
|             (shard + 1) % T::ShardCount::to_u64() | ||||
|         } else { | ||||
|             shard | ||||
|         }; | ||||
| 
 | ||||
|         for &index in state | ||||
|             .get_crosslink_committee_for_shard(fake_shard, relative_epoch)? | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use super::per_block_processing::{errors::BlockProcessingError, process_deposits}; | ||||
| use super::per_block_processing::{errors::BlockProcessingError, process_deposit}; | ||||
| use crate::common::get_compact_committees_root; | ||||
| use tree_hash::TreeHash; | ||||
| use types::typenum::U4294967296; | ||||
| @ -32,7 +32,7 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>( | ||||
|     for (index, deposit) in deposits.into_iter().enumerate() { | ||||
|         let deposit_data_list = VariableList::<_, U4294967296>::from(leaves[..=index].to_vec()); | ||||
|         state.eth1_data.deposit_root = Hash256::from_slice(&deposit_data_list.tree_hash_root()); | ||||
|         process_deposits(&mut state, &[deposit], spec)?; | ||||
|         process_deposit(&mut state, &deposit, spec, true)?; | ||||
|     } | ||||
| 
 | ||||
|     // Process activations
 | ||||
| @ -48,6 +48,9 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>( | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Now that we have our validators, initialize the caches (including the committees)
 | ||||
|     state.build_all_caches(spec)?; | ||||
| 
 | ||||
|     // Populate active_index_roots and compact_committees_roots
 | ||||
|     let indices_list = VariableList::<usize, T::ValidatorRegistryLimit>::from( | ||||
|         state.get_active_validator_indices(T::genesis_epoch()), | ||||
| @ -59,3 +62,12 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>( | ||||
| 
 | ||||
|     Ok(state) | ||||
| } | ||||
| 
 | ||||
| /// Determine whether a candidate genesis state is suitable for starting the chain.
 | ||||
| ///
 | ||||
| /// Spec v0.8.1
 | ||||
| pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSpec) -> bool { | ||||
|     state.genesis_time >= spec.min_genesis_time | ||||
|         && state.get_active_validator_indices(T::genesis_epoch()).len() as u64 | ||||
|             >= spec.min_genesis_active_validator_count | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,7 @@ pub mod per_block_processing; | ||||
| pub mod per_epoch_processing; | ||||
| pub mod per_slot_processing; | ||||
| 
 | ||||
| pub use genesis::initialize_beacon_state_from_eth1; | ||||
| pub use genesis::{initialize_beacon_state_from_eth1, is_valid_genesis_state}; | ||||
| pub use per_block_processing::{ | ||||
|     errors::{BlockInvalid, BlockProcessingError}, | ||||
|     per_block_processing, per_block_processing_without_verifying_block_signature, | ||||
|  | ||||
| @ -358,7 +358,7 @@ pub fn process_deposits<T: EthSpec>( | ||||
|         Invalid::DepositCountInvalid | ||||
|     ); | ||||
| 
 | ||||
|     // Verify deposits in parallel.
 | ||||
|     // Verify merkle proofs in parallel.
 | ||||
|     deposits | ||||
|         .par_iter() | ||||
|         .enumerate() | ||||
| @ -368,47 +368,67 @@ pub fn process_deposits<T: EthSpec>( | ||||
|         })?; | ||||
| 
 | ||||
|     // Update the state in series.
 | ||||
|     for (i, deposit) in deposits.iter().enumerate() { | ||||
|         state.eth1_deposit_index += 1; | ||||
|     for deposit in deposits { | ||||
|         process_deposit(state, deposit, spec, false)?; | ||||
|     } | ||||
| 
 | ||||
|         // Ensure the state's pubkey cache is fully up-to-date, it will be used to check to see if the
 | ||||
|         // depositing validator already exists in the registry.
 | ||||
|         state.update_pubkey_cache()?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
|         // Get an `Option<u64>` where `u64` is the validator index if this deposit public key
 | ||||
|         // already exists in the beacon_state.
 | ||||
|         let validator_index = | ||||
|             get_existing_validator_index(state, deposit).map_err(|e| e.into_with_index(i))?; | ||||
| /// Process a single deposit, optionally verifying its merkle proof.
 | ||||
| ///
 | ||||
| /// Spec v0.8.1
 | ||||
| pub fn process_deposit<T: EthSpec>( | ||||
|     state: &mut BeaconState<T>, | ||||
|     deposit: &Deposit, | ||||
|     spec: &ChainSpec, | ||||
|     verify_merkle_proof: bool, | ||||
| ) -> Result<(), Error> { | ||||
|     let deposit_index = state.eth1_deposit_index as usize; | ||||
|     if verify_merkle_proof { | ||||
|         verify_deposit_merkle_proof(state, deposit, state.eth1_deposit_index, spec) | ||||
|             .map_err(|e| e.into_with_index(deposit_index))?; | ||||
|     } | ||||
| 
 | ||||
|         let amount = deposit.data.amount; | ||||
|     state.eth1_deposit_index += 1; | ||||
| 
 | ||||
|         if let Some(index) = validator_index { | ||||
|             // Update the existing validator balance.
 | ||||
|             safe_add_assign!(state.balances[index as usize], amount); | ||||
|         } else { | ||||
|             // The signature should be checked for new validators. Return early for a bad
 | ||||
|             // signature.
 | ||||
|             if verify_deposit_signature(state, deposit, spec).is_err() { | ||||
|                 return Ok(()); | ||||
|             } | ||||
|     // Ensure the state's pubkey cache is fully up-to-date, it will be used to check to see if the
 | ||||
|     // depositing validator already exists in the registry.
 | ||||
|     state.update_pubkey_cache()?; | ||||
| 
 | ||||
|             // Create a new validator.
 | ||||
|             let validator = Validator { | ||||
|                 pubkey: deposit.data.pubkey.clone(), | ||||
|                 withdrawal_credentials: deposit.data.withdrawal_credentials, | ||||
|                 activation_eligibility_epoch: spec.far_future_epoch, | ||||
|                 activation_epoch: spec.far_future_epoch, | ||||
|                 exit_epoch: spec.far_future_epoch, | ||||
|                 withdrawable_epoch: spec.far_future_epoch, | ||||
|                 effective_balance: std::cmp::min( | ||||
|                     amount - amount % spec.effective_balance_increment, | ||||
|                     spec.max_effective_balance, | ||||
|                 ), | ||||
|                 slashed: false, | ||||
|             }; | ||||
|             state.validators.push(validator)?; | ||||
|             state.balances.push(deposit.data.amount)?; | ||||
|     // Get an `Option<u64>` where `u64` is the validator index if this deposit public key
 | ||||
|     // already exists in the beacon_state.
 | ||||
|     let validator_index = get_existing_validator_index(state, deposit) | ||||
|         .map_err(|e| e.into_with_index(deposit_index))?; | ||||
| 
 | ||||
|     let amount = deposit.data.amount; | ||||
| 
 | ||||
|     if let Some(index) = validator_index { | ||||
|         // Update the existing validator balance.
 | ||||
|         safe_add_assign!(state.balances[index as usize], amount); | ||||
|     } else { | ||||
|         // The signature should be checked for new validators. Return early for a bad
 | ||||
|         // signature.
 | ||||
|         if verify_deposit_signature(state, deposit, spec).is_err() { | ||||
|             return Ok(()); | ||||
|         } | ||||
| 
 | ||||
|         // Create a new validator.
 | ||||
|         let validator = Validator { | ||||
|             pubkey: deposit.data.pubkey.clone(), | ||||
|             withdrawal_credentials: deposit.data.withdrawal_credentials, | ||||
|             activation_eligibility_epoch: spec.far_future_epoch, | ||||
|             activation_epoch: spec.far_future_epoch, | ||||
|             exit_epoch: spec.far_future_epoch, | ||||
|             withdrawable_epoch: spec.far_future_epoch, | ||||
|             effective_balance: std::cmp::min( | ||||
|                 amount - amount % spec.effective_balance_increment, | ||||
|                 spec.max_effective_balance, | ||||
|             ), | ||||
|             slashed: false, | ||||
|         }; | ||||
|         state.validators.push(validator)?; | ||||
|         state.balances.push(deposit.data.amount)?; | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
|  | ||||
| @ -33,11 +33,8 @@ impl PubkeyCache { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Inserts a validator index into the map.
 | ||||
|     ///
 | ||||
|     /// The added index must equal the number of validators already added to the map. This ensures
 | ||||
|     /// that an index is never skipped.
 | ||||
|     /// Looks up a validator index's by their public key.
 | ||||
|     pub fn get(&self, pubkey: &PublicKey) -> Option<ValidatorIndex> { | ||||
|         self.map.get(pubkey).cloned() | ||||
|         self.map.get(pubkey).copied() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,8 @@ mod epoch_processing_final_updates; | ||||
| mod epoch_processing_justification_and_finalization; | ||||
| mod epoch_processing_registry_updates; | ||||
| mod epoch_processing_slashings; | ||||
| mod genesis_initialization; | ||||
| mod genesis_validity; | ||||
| mod operations_attestation; | ||||
| mod operations_attester_slashing; | ||||
| mod operations_block_header; | ||||
| @ -36,6 +38,8 @@ pub use epoch_processing_final_updates::*; | ||||
| pub use epoch_processing_justification_and_finalization::*; | ||||
| pub use epoch_processing_registry_updates::*; | ||||
| pub use epoch_processing_slashings::*; | ||||
| pub use genesis_initialization::*; | ||||
| pub use genesis_validity::*; | ||||
| pub use operations_attestation::*; | ||||
| pub use operations_attester_slashing::*; | ||||
| pub use operations_block_header::*; | ||||
|  | ||||
							
								
								
									
										45
									
								
								tests/ef_tests/src/cases/genesis_initialization.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/ef_tests/src/cases/genesis_initialization.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| use super::*; | ||||
| use crate::bls_setting::BlsSetting; | ||||
| use crate::case_result::compare_beacon_state_results_without_caches; | ||||
| use serde_derive::Deserialize; | ||||
| use state_processing::initialize_beacon_state_from_eth1; | ||||
| use types::{BeaconState, Deposit, EthSpec, Hash256}; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
| #[serde(bound = "E: EthSpec")] | ||||
| pub struct GenesisInitialization<E: EthSpec> { | ||||
|     pub description: String, | ||||
|     pub bls_setting: Option<BlsSetting>, | ||||
|     pub eth1_block_hash: Hash256, | ||||
|     pub eth1_timestamp: u64, | ||||
|     pub deposits: Vec<Deposit>, | ||||
|     pub state: Option<BeaconState<E>>, | ||||
| } | ||||
| 
 | ||||
| impl<E: EthSpec> YamlDecode for GenesisInitialization<E> { | ||||
|     fn yaml_decode(yaml: &str) -> Result<Self, Error> { | ||||
|         Ok(serde_yaml::from_str(yaml).unwrap()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<E: EthSpec> Case for GenesisInitialization<E> { | ||||
|     fn description(&self) -> String { | ||||
|         self.description.clone() | ||||
|     } | ||||
| 
 | ||||
|     fn result(&self, _case_index: usize) -> Result<(), Error> { | ||||
|         self.bls_setting.unwrap_or_default().check()?; | ||||
|         let spec = &E::default_spec(); | ||||
| 
 | ||||
|         let mut result = initialize_beacon_state_from_eth1( | ||||
|             self.eth1_block_hash, | ||||
|             self.eth1_timestamp, | ||||
|             self.deposits.clone(), | ||||
|             spec, | ||||
|         ); | ||||
| 
 | ||||
|         let mut expected = self.state.clone(); | ||||
| 
 | ||||
|         compare_beacon_state_results_without_caches(&mut result, &mut expected) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								tests/ef_tests/src/cases/genesis_validity.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								tests/ef_tests/src/cases/genesis_validity.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| use super::*; | ||||
| use crate::bls_setting::BlsSetting; | ||||
| use serde_derive::Deserialize; | ||||
| use state_processing::is_valid_genesis_state; | ||||
| use types::{BeaconState, EthSpec}; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
| #[serde(bound = "E: EthSpec")] | ||||
| pub struct GenesisValidity<E: EthSpec> { | ||||
|     pub description: String, | ||||
|     pub bls_setting: Option<BlsSetting>, | ||||
|     pub genesis: BeaconState<E>, | ||||
|     pub is_valid: bool, | ||||
| } | ||||
| 
 | ||||
| impl<E: EthSpec> YamlDecode for GenesisValidity<E> { | ||||
|     fn yaml_decode(yaml: &str) -> Result<Self, Error> { | ||||
|         Ok(serde_yaml::from_str(yaml).unwrap()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<E: EthSpec> Case for GenesisValidity<E> { | ||||
|     fn description(&self) -> String { | ||||
|         self.description.clone() | ||||
|     } | ||||
| 
 | ||||
|     fn result(&self, _case_index: usize) -> Result<(), Error> { | ||||
|         self.bls_setting.unwrap_or_default().check()?; | ||||
|         let spec = &E::default_spec(); | ||||
| 
 | ||||
|         let is_valid = is_valid_genesis_state(&self.genesis, spec); | ||||
| 
 | ||||
|         if is_valid == self.is_valid { | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(Error::NotEqual(format!( | ||||
|                 "Got {}, expected {}", | ||||
|                 is_valid, self.is_valid | ||||
|             ))) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -134,6 +134,14 @@ impl Doc { | ||||
|                 // FIXME: skipped due to compact committees issue
 | ||||
|                 // run_test::<EpochProcessingFinalUpdates<MainnetEthSpec>>(self)
 | ||||
|             } | ||||
|             ("genesis", "initialization", "minimal") => { | ||||
|                 run_test::<GenesisInitialization<MinimalEthSpec>>(self) | ||||
|             } | ||||
|             ("genesis", "initialization", "mainnet") => { | ||||
|                 run_test::<GenesisInitialization<MainnetEthSpec>>(self) | ||||
|             } | ||||
|             ("genesis", "validity", "minimal") => run_test::<GenesisValidity<MinimalEthSpec>>(self), | ||||
|             ("genesis", "validity", "mainnet") => run_test::<GenesisValidity<MainnetEthSpec>>(self), | ||||
|             (runner, handler, config) => panic!( | ||||
|                 "No implementation for runner: \"{}\", handler: \"{}\", config: \"{}\"", | ||||
|                 runner, handler, config | ||||
|  | ||||
| @ -205,3 +205,21 @@ fn epoch_processing_final_updates() { | ||||
|             Doc::assert_tests_pass(file); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn genesis_initialization() { | ||||
|     yaml_files_in_test_dir(&Path::new("genesis").join("initialization")) | ||||
|         .into_par_iter() | ||||
|         .for_each(|file| { | ||||
|             Doc::assert_tests_pass(file); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn genesis_validity() { | ||||
|     yaml_files_in_test_dir(&Path::new("genesis").join("validity")) | ||||
|         .into_par_iter() | ||||
|         .for_each(|file| { | ||||
|             Doc::assert_tests_pass(file); | ||||
|         }); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user