Fix issues with building on genesis block
This commit is contained in:
		
							parent
							
								
									191761f356
								
							
						
					
					
						commit
						edeace9e75
					
				| @ -82,20 +82,18 @@ where | ||||
|         let state_root = genesis_state.canonical_root(); | ||||
|         state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?; | ||||
| 
 | ||||
|         let block_root = genesis_block.canonical_root(); | ||||
|         let block_root = genesis_block.into_header().canonical_root(); | ||||
|         block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?; | ||||
| 
 | ||||
|         let finalized_head = RwLock::new(CheckPoint::new( | ||||
|             genesis_block.clone(), | ||||
|             block_root, | ||||
|             // TODO: this is a memory waste; remove full clone.
 | ||||
|             genesis_state.clone(), | ||||
|             state_root, | ||||
|         )); | ||||
|         let canonical_head = RwLock::new(CheckPoint::new( | ||||
|             genesis_block.clone(), | ||||
|             block_root, | ||||
|             // TODO: this is a memory waste; remove full clone.
 | ||||
|             genesis_state.clone(), | ||||
|             state_root, | ||||
|         )); | ||||
| @ -190,10 +188,13 @@ where | ||||
|     /// processing applied to it.
 | ||||
|     pub fn advance_state(&self, slot: Slot) -> Result<(), SlotProcessingError> { | ||||
|         let state_slot = self.state.read().slot; | ||||
|         let head_block_root = self.head().beacon_block_root; | ||||
| 
 | ||||
|         let latest_block_header = self.head().beacon_block.into_header(); | ||||
| 
 | ||||
|         for _ in state_slot.as_u64()..slot.as_u64() { | ||||
|             per_slot_processing(&mut *self.state.write(), head_block_root, &self.spec)?; | ||||
|             per_slot_processing(&mut *self.state.write(), &latest_block_header, &self.spec)?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| @ -554,66 +555,13 @@ where | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Dumps the entire canonical chain, from the head to genesis to a vector for analysis.
 | ||||
|     ///
 | ||||
|     /// This could be a very expensive operation and should only be done in testing/analysis
 | ||||
|     /// activities.
 | ||||
|     pub fn chain_dump(&self) -> Result<Vec<CheckPoint>, Error> { | ||||
|         let mut dump = vec![]; | ||||
| 
 | ||||
|         let mut last_slot = CheckPoint { | ||||
|             beacon_block: self.head().beacon_block.clone(), | ||||
|             beacon_block_root: self.head().beacon_block_root, | ||||
|             beacon_state: self.head().beacon_state.clone(), | ||||
|             beacon_state_root: self.head().beacon_state_root, | ||||
|         }; | ||||
| 
 | ||||
|         dump.push(last_slot.clone()); | ||||
| 
 | ||||
|         loop { | ||||
|             let beacon_block_root = last_slot.beacon_block.previous_block_root; | ||||
| 
 | ||||
|             if beacon_block_root == self.spec.zero_hash { | ||||
|                 break; // Genesis has been reached.
 | ||||
|             } | ||||
| 
 | ||||
|             let beacon_block = self | ||||
|                 .block_store | ||||
|                 .get_deserialized(&beacon_block_root)? | ||||
|                 .ok_or_else(|| { | ||||
|                     Error::DBInconsistent(format!("Missing block {}", beacon_block_root)) | ||||
|                 })?; | ||||
|             let beacon_state_root = beacon_block.state_root; | ||||
|             let beacon_state = self | ||||
|                 .state_store | ||||
|                 .get_deserialized(&beacon_state_root)? | ||||
|                 .ok_or_else(|| { | ||||
|                     Error::DBInconsistent(format!("Missing state {}", beacon_state_root)) | ||||
|                 })?; | ||||
| 
 | ||||
|             let slot = CheckPoint { | ||||
|                 beacon_block, | ||||
|                 beacon_block_root, | ||||
|                 beacon_state, | ||||
|                 beacon_state_root, | ||||
|             }; | ||||
| 
 | ||||
|             dump.push(slot.clone()); | ||||
|             last_slot = slot; | ||||
|         } | ||||
| 
 | ||||
|         dump.reverse(); | ||||
| 
 | ||||
|         Ok(dump) | ||||
|     } | ||||
| 
 | ||||
|     /// Accept some block and attempt to add it to block DAG.
 | ||||
|     ///
 | ||||
|     /// Will accept blocks from prior slots, however it will reject any block from a future slot.
 | ||||
|     pub fn process_block(&self, block: BeaconBlock) -> Result<BlockProcessingOutcome, Error> { | ||||
|         debug!("Processing block with slot {}...", block.slot); | ||||
| 
 | ||||
|         let block_root = block.canonical_root(); | ||||
|         let block_root = block.into_header().canonical_root(); | ||||
| 
 | ||||
|         let present_slot = self.present_slot(); | ||||
| 
 | ||||
| @ -648,8 +596,10 @@ where | ||||
| 
 | ||||
|         // Transition the parent state to the present slot.
 | ||||
|         let mut state = parent_state; | ||||
|         println!("parent process state: {:?}", state.latest_block_header); | ||||
|         let previous_block_header = parent_block.into_header(); | ||||
|         for _ in state.slot.as_u64()..present_slot.as_u64() { | ||||
|             if let Err(e) = per_slot_processing(&mut state, parent_block_root, &self.spec) { | ||||
|             if let Err(e) = per_slot_processing(&mut state, &previous_block_header, &self.spec) { | ||||
|                 return Ok(BlockProcessingOutcome::InvalidBlock( | ||||
|                     InvalidBlock::SlotProcessingError(e), | ||||
|                 )); | ||||
| @ -664,6 +614,8 @@ where | ||||
|             )); | ||||
|         } | ||||
| 
 | ||||
|         println!("process state: {:?}", state.latest_block_header); | ||||
| 
 | ||||
|         let state_root = state.canonical_root(); | ||||
| 
 | ||||
|         if block.state_root != state_root { | ||||
| @ -726,7 +678,7 @@ where | ||||
|         ); | ||||
| 
 | ||||
|         let previous_block_root = *state | ||||
|             .get_block_root(state.slot.saturating_sub(1_u64), &self.spec) | ||||
|             .get_block_root(state.slot - 1, &self.spec) | ||||
|             .map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?; | ||||
| 
 | ||||
|         let mut block = BeaconBlock { | ||||
| @ -754,6 +706,8 @@ where | ||||
| 
 | ||||
|         per_block_processing_without_verifying_block_signature(&mut state, &block, &self.spec)?; | ||||
| 
 | ||||
|         println!("produce state: {:?}", state.latest_block_header); | ||||
| 
 | ||||
|         let state_root = state.canonical_root(); | ||||
| 
 | ||||
|         block.state_root = state_root; | ||||
| @ -788,6 +742,59 @@ where | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Dumps the entire canonical chain, from the head to genesis to a vector for analysis.
 | ||||
|     ///
 | ||||
|     /// This could be a very expensive operation and should only be done in testing/analysis
 | ||||
|     /// activities.
 | ||||
|     pub fn chain_dump(&self) -> Result<Vec<CheckPoint>, Error> { | ||||
|         let mut dump = vec![]; | ||||
| 
 | ||||
|         let mut last_slot = CheckPoint { | ||||
|             beacon_block: self.head().beacon_block.clone(), | ||||
|             beacon_block_root: self.head().beacon_block_root, | ||||
|             beacon_state: self.head().beacon_state.clone(), | ||||
|             beacon_state_root: self.head().beacon_state_root, | ||||
|         }; | ||||
| 
 | ||||
|         dump.push(last_slot.clone()); | ||||
| 
 | ||||
|         loop { | ||||
|             let beacon_block_root = last_slot.beacon_block.previous_block_root; | ||||
| 
 | ||||
|             if beacon_block_root == self.spec.zero_hash { | ||||
|                 break; // Genesis has been reached.
 | ||||
|             } | ||||
| 
 | ||||
|             let beacon_block = self | ||||
|                 .block_store | ||||
|                 .get_deserialized(&beacon_block_root)? | ||||
|                 .ok_or_else(|| { | ||||
|                     Error::DBInconsistent(format!("Missing block {}", beacon_block_root)) | ||||
|                 })?; | ||||
|             let beacon_state_root = beacon_block.state_root; | ||||
|             let beacon_state = self | ||||
|                 .state_store | ||||
|                 .get_deserialized(&beacon_state_root)? | ||||
|                 .ok_or_else(|| { | ||||
|                     Error::DBInconsistent(format!("Missing state {}", beacon_state_root)) | ||||
|                 })?; | ||||
| 
 | ||||
|             let slot = CheckPoint { | ||||
|                 beacon_block, | ||||
|                 beacon_block_root, | ||||
|                 beacon_state, | ||||
|                 beacon_state_root, | ||||
|             }; | ||||
| 
 | ||||
|             dump.push(slot.clone()); | ||||
|             last_slot = slot; | ||||
|         } | ||||
| 
 | ||||
|         dump.reverse(); | ||||
| 
 | ||||
|         Ok(dump) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<DBError> for Error { | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| use crate::*; | ||||
| use types::{BeaconState, BeaconStateError, ChainSpec, Hash256}; | ||||
| use ssz::TreeHash; | ||||
| use types::*; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq)] | ||||
| pub enum Error { | ||||
| @ -12,9 +13,11 @@ pub enum Error { | ||||
| /// Spec v0.5.0
 | ||||
| pub fn per_slot_processing( | ||||
|     state: &mut BeaconState, | ||||
|     previous_block_root: Hash256, | ||||
|     latest_block_header: &BeaconBlockHeader, | ||||
|     spec: &ChainSpec, | ||||
| ) -> Result<(), Error> { | ||||
|     cache_state(state, latest_block_header, spec)?; | ||||
| 
 | ||||
|     if (state.slot + 1) % spec.slots_per_epoch == 0 { | ||||
|         per_epoch_processing(state, spec)?; | ||||
|         state.advance_caches(); | ||||
| @ -22,6 +25,37 @@ pub fn per_slot_processing( | ||||
| 
 | ||||
|     state.slot += 1; | ||||
| 
 | ||||
|     let latest_block_root = Hash256::from_slice(&state.latest_block_header.hash_tree_root()[..]); | ||||
|     state.set_block_root(state.slot - 1, latest_block_root, spec)?; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn cache_state( | ||||
|     state: &mut BeaconState, | ||||
|     latest_block_header: &BeaconBlockHeader, | ||||
|     spec: &ChainSpec, | ||||
| ) -> Result<(), Error> { | ||||
|     let previous_slot_state_root = Hash256::from_slice(&state.hash_tree_root()[..]); | ||||
| 
 | ||||
|     // Note: increment the state slot here to allow use of our `state_root` and `block_root`
 | ||||
|     // getter/setter functions.
 | ||||
|     //
 | ||||
|     // This is a bit hacky, however it gets the job safely without lots of code.
 | ||||
|     let previous_slot = state.slot; | ||||
|     state.slot += 1; | ||||
| 
 | ||||
|     // Store the previous slot's post-state transition root.
 | ||||
|     if state.latest_block_header.state_root == spec.zero_hash { | ||||
|         state.latest_block_header.state_root = previous_slot_state_root | ||||
|     } | ||||
| 
 | ||||
|     let latest_block_root = Hash256::from_slice(&latest_block_header.hash_tree_root()[..]); | ||||
|     state.set_block_root(previous_slot, latest_block_root, spec)?; | ||||
| 
 | ||||
|     // Set the state slot back to what it should be.
 | ||||
|     state.slot -= 1; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -63,16 +63,32 @@ impl BeaconBlock { | ||||
|         Hash256::from_slice(&self.hash_tree_root()[..]) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns a full `BeaconBlockHeader` of this block.
 | ||||
|     ///
 | ||||
|     /// Note: This method is used instead of an `Into` impl to avoid a `Clone` of an entire block
 | ||||
|     /// when you want to have the block _and_ the header.
 | ||||
|     ///
 | ||||
|     /// Note: performs a full tree-hash of `self.body`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn into_header(&self) -> BeaconBlockHeader { | ||||
|         BeaconBlockHeader { | ||||
|             slot: self.slot, | ||||
|             previous_block_root: self.previous_block_root, | ||||
|             state_root: self.state_root, | ||||
|             block_body_root: Hash256::from_slice(&self.body.hash_tree_root()[..]), | ||||
|             signature: self.signature.clone(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Returns a "temporary" header, where the `state_root` is `spec.zero_hash`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn into_temporary_header(&self, spec: &ChainSpec) -> BeaconBlockHeader { | ||||
|         BeaconBlockHeader { | ||||
|             slot: self.slot, | ||||
|             previous_block_root: self.previous_block_root, | ||||
|             state_root: spec.zero_hash, | ||||
|             block_body_root: Hash256::from_slice(&self.hash_tree_root()), | ||||
|             signature: self.signature.clone(), | ||||
|             signature: spec.empty_signature.clone(), | ||||
|             ..self.into_header() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -30,6 +30,15 @@ pub struct BeaconBlockHeader { | ||||
|     pub signature: Signature, | ||||
| } | ||||
| 
 | ||||
| impl BeaconBlockHeader { | ||||
|     /// Returns the `hash_tree_root` of the header.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn canonical_root(&self) -> Hash256 { | ||||
|         Hash256::from_slice(&self.hash_tree_root()[..]) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|  | ||||
| @ -35,6 +35,7 @@ pub enum Error { | ||||
|     InsufficientAttestations, | ||||
|     InsufficientCommittees, | ||||
|     InsufficientSlashedBalances, | ||||
|     InsufficientStateRoots, | ||||
|     NoCommitteeForShard, | ||||
|     EpochCacheUninitialized(RelativeEpoch), | ||||
|     PubkeyCacheInconsistent, | ||||
| @ -425,6 +426,22 @@ impl BeaconState { | ||||
|             .ok_or_else(|| Error::NoCommitteeForShard)?) | ||||
|     } | ||||
| 
 | ||||
|     /// Safely obtains the index for latest block roots, given some `slot`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     fn get_latest_block_roots_index(&self, slot: Slot, spec: &ChainSpec) -> Result<usize, Error> { | ||||
|         if (slot < self.slot) && (self.slot <= slot + spec.slots_per_historical_root as u64) { | ||||
|             let i = slot.as_usize() % spec.slots_per_historical_root; | ||||
|             if i >= self.latest_block_roots.len() { | ||||
|                 Err(Error::InsufficientStateRoots) | ||||
|             } else { | ||||
|                 Ok(i) | ||||
|             } | ||||
|         } else { | ||||
|             Err(BeaconStateError::SlotOutOfBounds) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Return the block root at a recent `slot`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
| @ -433,13 +450,21 @@ impl BeaconState { | ||||
|         slot: Slot, | ||||
|         spec: &ChainSpec, | ||||
|     ) -> Result<&Hash256, BeaconStateError> { | ||||
|         if (self.slot <= slot + spec.slots_per_historical_root as u64) && (slot < self.slot) { | ||||
|             self.latest_block_roots | ||||
|                 .get(slot.as_usize() % spec.slots_per_historical_root) | ||||
|                 .ok_or_else(|| Error::InsufficientBlockRoots) | ||||
|         } else { | ||||
|             Err(Error::EpochOutOfBounds) | ||||
|         } | ||||
|         let i = self.get_latest_block_roots_index(slot, spec)?; | ||||
|         Ok(&self.latest_block_roots[i]) | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the block root for some given slot.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn set_block_root( | ||||
|         &mut self, | ||||
|         slot: Slot, | ||||
|         block_root: Hash256, | ||||
|         spec: &ChainSpec, | ||||
|     ) -> Result<(), BeaconStateError> { | ||||
|         let i = self.get_latest_block_roots_index(slot, spec)?; | ||||
|         Ok(self.latest_block_roots[i] = block_root) | ||||
|     } | ||||
| 
 | ||||
|     /// XOR-assigns the existing `epoch` randao mix with the hash of the `signature`.
 | ||||
| @ -506,6 +531,43 @@ impl BeaconState { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Safely obtains the index for latest state roots, given some `slot`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     fn get_latest_state_roots_index(&self, slot: Slot, spec: &ChainSpec) -> Result<usize, Error> { | ||||
|         if (slot < self.slot) && (self.slot <= slot + spec.slots_per_historical_root as u64) { | ||||
|             let i = slot.as_usize() % spec.slots_per_historical_root; | ||||
|             if i >= self.latest_state_roots.len() { | ||||
|                 Err(Error::InsufficientStateRoots) | ||||
|             } else { | ||||
|                 Ok(i) | ||||
|             } | ||||
|         } else { | ||||
|             Err(BeaconStateError::SlotOutOfBounds) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Gets the state root for some slot.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn get_state_root(&mut self, slot: Slot, spec: &ChainSpec) -> Result<&Hash256, Error> { | ||||
|         let i = self.get_latest_state_roots_index(slot, spec)?; | ||||
|         Ok(&self.latest_state_roots[i]) | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the latest state root for slot.
 | ||||
|     ///
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn set_state_root( | ||||
|         &mut self, | ||||
|         slot: Slot, | ||||
|         state_root: Hash256, | ||||
|         spec: &ChainSpec, | ||||
|     ) -> Result<(), Error> { | ||||
|         let i = self.get_latest_state_roots_index(slot, spec)?; | ||||
|         Ok(self.latest_state_roots[i] = state_root) | ||||
|     } | ||||
| 
 | ||||
|     /// Generate a seed for the given `epoch`.
 | ||||
|     ///
 | ||||
|     /// Spec v0.4.0
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user