Fix bug with epoch caches, add tests
This commit is contained in:
		
							parent
							
								
									f71cab8ba2
								
							
						
					
					
						commit
						8677b9e9cc
					
				| @ -32,7 +32,7 @@ const VERIFY_DEPOSIT_MERKLE_PROOFS: bool = false; | ||||
| /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
 | ||||
| /// returns an error describing why the block was invalid or how the function failed to execute.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| pub fn per_block_processing( | ||||
|     state: &mut BeaconState, | ||||
|     block: &BeaconBlock, | ||||
| @ -47,7 +47,7 @@ pub fn per_block_processing( | ||||
| /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
 | ||||
| /// returns an error describing why the block was invalid or how the function failed to execute.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| pub fn per_block_processing_without_verifying_block_signature( | ||||
|     state: &mut BeaconState, | ||||
|     block: &BeaconBlock, | ||||
| @ -62,7 +62,7 @@ pub fn per_block_processing_without_verifying_block_signature( | ||||
| /// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
 | ||||
| /// returns an error describing why the block was invalid or how the function failed to execute.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| fn per_block_processing_signature_optional( | ||||
|     mut state: &mut BeaconState, | ||||
|     block: &BeaconBlock, | ||||
|  | ||||
| @ -10,7 +10,7 @@ use types::*; | ||||
| ///
 | ||||
| /// Returns `Ok(())` if the `SlashableAttestation` is valid, otherwise indicates the reason for invalidity.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| pub fn verify_slashable_attestation( | ||||
|     state: &BeaconState, | ||||
|     slashable_attestation: &SlashableAttestation, | ||||
|  | ||||
| @ -94,7 +94,7 @@ pub fn verify_transfer( | ||||
| ///
 | ||||
| /// Does not check that the transfer is valid, however checks for overflow in all actions.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| pub fn execute_transfer( | ||||
|     state: &mut BeaconState, | ||||
|     transfer: &Transfer, | ||||
|  | ||||
| @ -279,7 +279,9 @@ impl BeaconState { | ||||
|     fn cache(&self, relative_epoch: RelativeEpoch, spec: &ChainSpec) -> Result<&EpochCache, Error> { | ||||
|         let cache = &self.caches[self.cache_index(relative_epoch)]; | ||||
| 
 | ||||
|         if cache.initialized_epoch == Some(self.slot.epoch(spec.slots_per_epoch)) { | ||||
|         let epoch = relative_epoch.into_epoch(self.slot.epoch(spec.slots_per_epoch)); | ||||
| 
 | ||||
|         if cache.initialized_epoch == Some(epoch) { | ||||
|             Ok(cache) | ||||
|         } else { | ||||
|             Err(Error::EpochCacheUninitialized(relative_epoch)) | ||||
|  | ||||
| @ -159,7 +159,7 @@ impl EpochCrosslinkCommittees { | ||||
|         let epoch_start_slot = self.epoch.start_slot(spec.slots_per_epoch); | ||||
|         let epoch_end_slot = self.epoch.end_slot(spec.slots_per_epoch); | ||||
| 
 | ||||
|         if (epoch_start_slot < slot) && (slot <= epoch_end_slot) { | ||||
|         if (epoch_start_slot <= slot) && (slot <= epoch_end_slot) { | ||||
|             let index = slot - epoch_start_slot; | ||||
|             self.crosslink_committees.get(index.as_usize()) | ||||
|         } else { | ||||
|  | ||||
| @ -1,5 +1,57 @@ | ||||
| #![cfg(test)] | ||||
| 
 | ||||
| use super::*; | ||||
| use crate::test_utils::*; | ||||
| 
 | ||||
| ssz_tests!(BeaconState); | ||||
| 
 | ||||
| /// Test that
 | ||||
| ///
 | ||||
| /// 1. Using the cache before it's built fails.
 | ||||
| /// 2. Using the cache after it's build passes.
 | ||||
| /// 3. Using the cache after it's dropped fails.
 | ||||
| fn test_cache_initialization<'a>( | ||||
|     state: &'a mut BeaconState, | ||||
|     relative_epoch: RelativeEpoch, | ||||
|     spec: &ChainSpec, | ||||
| ) { | ||||
|     let slot = relative_epoch | ||||
|         .into_epoch(state.slot.epoch(spec.slots_per_epoch)) | ||||
|         .start_slot(spec.slots_per_epoch); | ||||
| 
 | ||||
|     // Assuming the cache isn't already built, assert that a call to a cache-using function fails.
 | ||||
|     assert_eq!( | ||||
|         state.get_beacon_proposer_index(slot, relative_epoch, spec), | ||||
|         Err(BeaconStateError::EpochCacheUninitialized(relative_epoch)) | ||||
|     ); | ||||
| 
 | ||||
|     // Build the cache.
 | ||||
|     state.build_epoch_cache(relative_epoch, spec).unwrap(); | ||||
| 
 | ||||
|     // Assert a call to a cache-using function passes.
 | ||||
|     let _ = state | ||||
|         .get_beacon_proposer_index(slot, relative_epoch, spec) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     // Drop the cache.
 | ||||
|     state.drop_cache(relative_epoch); | ||||
| 
 | ||||
|     // Assert a call to a cache-using function fail.
 | ||||
|     assert_eq!( | ||||
|         state.get_beacon_proposer_index(slot, relative_epoch, spec), | ||||
|         Err(BeaconStateError::EpochCacheUninitialized(relative_epoch)) | ||||
|     ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn cache_initialization() { | ||||
|     let spec = ChainSpec::few_validators(); | ||||
|     let (mut state, _keypairs) = | ||||
|         TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec).build(); | ||||
| 
 | ||||
|     state.slot = (spec.genesis_epoch + 1).start_slot(spec.slots_per_epoch); | ||||
| 
 | ||||
|     test_cache_initialization(&mut state, RelativeEpoch::Previous, &spec); | ||||
|     test_cache_initialization(&mut state, RelativeEpoch::Current, &spec); | ||||
|     test_cache_initialization(&mut state, RelativeEpoch::NextWithRegistryChange, &spec); | ||||
|     test_cache_initialization(&mut state, RelativeEpoch::NextWithoutRegistryChange, &spec); | ||||
| } | ||||
|  | ||||
| @ -74,3 +74,61 @@ impl RelativeEpoch { | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn test_into_epoch() { | ||||
|         let base = Epoch::new(10); | ||||
| 
 | ||||
|         assert_eq!(RelativeEpoch::Current.into_epoch(base), base); | ||||
|         assert_eq!(RelativeEpoch::Previous.into_epoch(base), base - 1); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::NextWithRegistryChange.into_epoch(base), | ||||
|             base + 1 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::NextWithoutRegistryChange.into_epoch(base), | ||||
|             base + 1 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn from_epoch() { | ||||
|         let base = Epoch::new(10); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_epoch(base, base - 1), | ||||
|             Ok(RelativeEpoch::Previous) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_epoch(base, base), | ||||
|             Ok(RelativeEpoch::Current) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_epoch(base, base + 1), | ||||
|             Err(RelativeEpochError::AmbiguiousNextEpoch) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn from_slot() { | ||||
|         let spec = ChainSpec::foundation(); | ||||
|         let base = Epoch::new(10).start_slot(spec.slots_per_epoch); | ||||
| 
 | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_slot(base, base - 1, &spec), | ||||
|             Ok(RelativeEpoch::Previous) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_slot(base, base, &spec), | ||||
|             Ok(RelativeEpoch::Current) | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             RelativeEpoch::from_slot(base, base + spec.slots_per_epoch, &spec), | ||||
|             Err(RelativeEpochError::AmbiguiousNextEpoch) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user