iterate over all epochs
This commit is contained in:
		
							parent
							
								
									af868a7439
								
							
						
					
					
						commit
						4d3f137e1e
					
				@ -419,6 +419,45 @@ impl<'a> Iterator for AncestryIter<'a> {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// An iterator which walks all epoch transitions.
 | 
				
			||||||
 | 
					/// Returns epoch transitions.
 | 
				
			||||||
 | 
					pub struct EpochTransitionIter<'a> {
 | 
				
			||||||
 | 
						chain: &'a BlockChain,
 | 
				
			||||||
 | 
						prefix_iter: Box<Iterator<Item=(Box<[u8]>, Box<[u8]>)> + 'a>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Iterator for EpochTransitionIter<'a> {
 | 
				
			||||||
 | 
						type Item = (u64, EpochTransition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn next(&mut self) -> Option<Self::Item> {
 | 
				
			||||||
 | 
							loop {
 | 
				
			||||||
 | 
								match self.prefix_iter.next() {
 | 
				
			||||||
 | 
									Some((key, val)) => {
 | 
				
			||||||
 | 
										// iterator may continue beyond values beginning with this
 | 
				
			||||||
 | 
										// prefix.
 | 
				
			||||||
 | 
										if !key.starts_with(&EPOCH_KEY_PREFIX[..]) { return None }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let transitions: EpochTransitions = ::rlp::decode(&val[..]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// if there are multiple candidates, at most one will be on the
 | 
				
			||||||
 | 
										// canon chain.
 | 
				
			||||||
 | 
										for transition in transitions.candidates.into_iter() {
 | 
				
			||||||
 | 
											let is_in_canon_chain = self.chain.block_hash(transition.block_number)
 | 
				
			||||||
 | 
												.map_or(false, |hash| hash == transition.block_hash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if is_in_canon_chain {
 | 
				
			||||||
 | 
												return Some((transitions.number, transition))
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// some epochs never occurred on the main chain.
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									None => return None,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl BlockChain {
 | 
					impl BlockChain {
 | 
				
			||||||
	/// Create new instance of blockchain from given Genesis.
 | 
						/// Create new instance of blockchain from given Genesis.
 | 
				
			||||||
	pub fn new(config: Config, genesis: &[u8], db: Arc<KeyValueDB>) -> BlockChain {
 | 
						pub fn new(config: Config, genesis: &[u8], db: Arc<KeyValueDB>) -> BlockChain {
 | 
				
			||||||
@ -817,6 +856,15 @@ impl BlockChain {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Iterate over all epoch transitions.
 | 
				
			||||||
 | 
						pub fn epoch_transitions(&self) -> EpochTransitionIter {
 | 
				
			||||||
 | 
							let iter = self.db.iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
 | 
				
			||||||
 | 
							EpochTransitionIter {
 | 
				
			||||||
 | 
								chain: self,
 | 
				
			||||||
 | 
								prefix_iter: iter,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Add a child to a given block. Assumes that the block hash is in
 | 
						/// Add a child to a given block. Assumes that the block hash is in
 | 
				
			||||||
	/// the chain and the child's parent is this block.
 | 
						/// the chain and the child's parent is this block.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
@ -2130,4 +2178,58 @@ mod tests {
 | 
				
			|||||||
		assert_eq!(bc.rewind(), Some(genesis_hash.clone()));
 | 
							assert_eq!(bc.rewind(), Some(genesis_hash.clone()));
 | 
				
			||||||
		assert_eq!(bc.rewind(), None);
 | 
							assert_eq!(bc.rewind(), None);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#[test]
 | 
				
			||||||
 | 
						fn epoch_transitions_iter() {
 | 
				
			||||||
 | 
							use blockchain::extras::EpochTransition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let mut canon_chain = ChainGenerator::default();
 | 
				
			||||||
 | 
							let mut finalizer = BlockFinalizer::default();
 | 
				
			||||||
 | 
							let genesis = canon_chain.generate(&mut finalizer).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let db = new_db();
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								let bc = new_chain(&genesis, db.clone());
 | 
				
			||||||
 | 
								let uncle = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let mut batch = db.transaction();
 | 
				
			||||||
 | 
								// create a longer fork
 | 
				
			||||||
 | 
								for i in 0..5 {
 | 
				
			||||||
 | 
									let canon_block = canon_chain.generate(&mut finalizer).unwrap();
 | 
				
			||||||
 | 
									let hash = BlockView::new(&canon_block).header_view().sha3();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									bc.insert_block(&mut batch, &canon_block, vec![]);
 | 
				
			||||||
 | 
									bc.insert_epoch_transition(&mut batch, i, EpochTransition {
 | 
				
			||||||
 | 
										block_hash: hash,
 | 
				
			||||||
 | 
										block_number: i + 1,
 | 
				
			||||||
 | 
										proof: vec![],
 | 
				
			||||||
 | 
										state_proof: vec![],
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
									bc.commit();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assert_eq!(bc.best_block_number(), 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let hash = BlockView::new(&uncle).header_view().sha3();
 | 
				
			||||||
 | 
								bc.insert_block(&mut batch, &uncle, vec![]);
 | 
				
			||||||
 | 
								bc.insert_epoch_transition(&mut batch, 999, EpochTransition {
 | 
				
			||||||
 | 
									block_hash: hash,
 | 
				
			||||||
 | 
									block_number: 1,
 | 
				
			||||||
 | 
									proof: vec![],
 | 
				
			||||||
 | 
									state_proof: vec![]
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								db.write(batch).unwrap();
 | 
				
			||||||
 | 
								bc.commit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// epoch 999 not in canonical chain.
 | 
				
			||||||
 | 
								assert_eq!(bc.epoch_transitions().map(|(i, _)| i).collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// re-loading the blockchain should load the correct best block.
 | 
				
			||||||
 | 
							let bc = new_chain(&genesis, db);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert_eq!(bc.best_block_number(), 5);
 | 
				
			||||||
 | 
							assert_eq!(bc.epoch_transitions().map(|(i, _)| i).collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -142,12 +142,9 @@ pub const EPOCH_KEY_LEN: usize = DB_PREFIX_LEN + 16;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// epoch key prefix.
 | 
					/// epoch key prefix.
 | 
				
			||||||
/// used to iterate over all epoch transitions in order from genesis.
 | 
					/// used to iterate over all epoch transitions in order from genesis.
 | 
				
			||||||
pub fn epoch_key_prefix() -> [u8; DB_PREFIX_LEN] {
 | 
					pub const EPOCH_KEY_PREFIX: &'static [u8; DB_PREFIX_LEN] = &[
 | 
				
			||||||
	let mut arr = [0u8; DB_PREFIX_LEN];
 | 
						ExtrasIndex::EpochTransitions as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
	arr[0] = ExtrasIndex::EpochTransitions as u8;
 | 
					];
 | 
				
			||||||
 | 
					 | 
				
			||||||
	arr
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
 | 
					pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
 | 
				
			||||||
impl Deref for EpochTransitionsKey {
 | 
					impl Deref for EpochTransitionsKey {
 | 
				
			||||||
@ -161,7 +158,7 @@ impl Key<EpochTransitions> for u64 {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fn key(&self) -> Self::Target {
 | 
						fn key(&self) -> Self::Target {
 | 
				
			||||||
		let mut arr = [0u8; EPOCH_KEY_LEN];
 | 
							let mut arr = [0u8; EPOCH_KEY_LEN];
 | 
				
			||||||
		arr[..DB_PREFIX_LEN].copy_from_slice(&epoch_key_prefix()[..]);
 | 
							arr[..DB_PREFIX_LEN].copy_from_slice(&EPOCH_KEY_PREFIX[..]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		write!(&mut arr[DB_PREFIX_LEN..], "{:016x}", self)
 | 
							write!(&mut arr[DB_PREFIX_LEN..], "{:016x}", self)
 | 
				
			||||||
			.expect("format arg is valid; no more than 16 chars will be written; qed");
 | 
								.expect("format arg is valid; no more than 16 chars will be written; qed");
 | 
				
			||||||
@ -302,14 +299,16 @@ impl Decodable for EpochTransitions {
 | 
				
			|||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct EpochTransition {
 | 
					pub struct EpochTransition {
 | 
				
			||||||
	pub block_hash: H256, // block hash at which the transition occurred.
 | 
						pub block_hash: H256, // block hash at which the transition occurred.
 | 
				
			||||||
 | 
						pub block_number: BlockNumber, // block number at which the tranition occurred.
 | 
				
			||||||
	pub proof: Vec<u8>, // "transition/epoch" proof from the engine.
 | 
						pub proof: Vec<u8>, // "transition/epoch" proof from the engine.
 | 
				
			||||||
	pub state_proof: Vec<DBValue>, // state items necessary to regenerate proof.
 | 
						pub state_proof: Vec<DBValue>, // state items necessary to regenerate proof.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Encodable for EpochTransition {
 | 
					impl Encodable for EpochTransition {
 | 
				
			||||||
	fn rlp_append(&self, s: &mut RlpStream) {
 | 
						fn rlp_append(&self, s: &mut RlpStream) {
 | 
				
			||||||
		s.begin_list(3)
 | 
							s.begin_list(4)
 | 
				
			||||||
			.append(&self.block_hash)
 | 
								.append(&self.block_hash)
 | 
				
			||||||
 | 
								.append(&self.block_number)
 | 
				
			||||||
			.append(&self.proof)
 | 
								.append(&self.proof)
 | 
				
			||||||
			.begin_list(self.state_proof.len());
 | 
								.begin_list(self.state_proof.len());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -323,8 +322,9 @@ impl Decodable for EpochTransition {
 | 
				
			|||||||
	fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
 | 
						fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
 | 
				
			||||||
		Ok(EpochTransition {
 | 
							Ok(EpochTransition {
 | 
				
			||||||
			block_hash: rlp.val_at(0)?,
 | 
								block_hash: rlp.val_at(0)?,
 | 
				
			||||||
			proof: rlp.val_at(1)?,
 | 
								block_number: rlp.val_at(1)?,
 | 
				
			||||||
			state_proof: rlp.at(2)?.iter().map(|x| {
 | 
								proof: rlp.val_at(2)?,
 | 
				
			||||||
 | 
								state_proof: rlp.at(3)?.iter().map(|x| {
 | 
				
			||||||
				Ok(DBValue::from_slice(x.data()?))
 | 
									Ok(DBValue::from_slice(x.data()?))
 | 
				
			||||||
			}).collect::<Result<Vec<_>, _>>()?,
 | 
								}).collect::<Result<Vec<_>, _>>()?,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
				
			|||||||
@ -667,6 +667,7 @@ impl Client {
 | 
				
			|||||||
			Ok(proof) =>
 | 
								Ok(proof) =>
 | 
				
			||||||
				chain.insert_epoch_transition(batch, epoch_number, EpochTransition {
 | 
									chain.insert_epoch_transition(batch, epoch_number, EpochTransition {
 | 
				
			||||||
					block_hash: hash.clone(),
 | 
										block_hash: hash.clone(),
 | 
				
			||||||
 | 
										block_number: header.number(),
 | 
				
			||||||
					proof: proof,
 | 
										proof: proof,
 | 
				
			||||||
					state_proof: read_values.into_inner().into_iter().collect(),
 | 
										state_proof: read_values.into_inner().into_iter().collect(),
 | 
				
			||||||
				}),
 | 
									}),
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user