Make block generator easier to use (#7888)
* Make block generator easier to use * applied review suggestions * rename BlockMetadata -> BlockOptions * removed redundant uses of blockchain generator and genereator.next().unwrap() calls
This commit is contained in:
		
							parent
							
								
									f8618dd02a
								
							
						
					
					
						commit
						c6b931766c
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										218
									
								
								ethcore/src/blockchain/generator.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								ethcore/src/blockchain/generator.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,218 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! Blockchain generator for tests.
 | 
			
		||||
 | 
			
		||||
use std::collections::VecDeque;
 | 
			
		||||
use ethereum_types::{U256, H256, Bloom};
 | 
			
		||||
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use header::Header;
 | 
			
		||||
use rlp::encode;
 | 
			
		||||
use transaction::SignedTransaction;
 | 
			
		||||
use views::BlockView;
 | 
			
		||||
 | 
			
		||||
/// Helper structure, used for encoding blocks.
 | 
			
		||||
#[derive(Default, Clone, RlpEncodable)]
 | 
			
		||||
pub struct Block {
 | 
			
		||||
	pub header: Header,
 | 
			
		||||
	pub transactions: Vec<SignedTransaction>,
 | 
			
		||||
	pub uncles: Vec<Header>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Block {
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn header(&self) -> Header {
 | 
			
		||||
		self.header.clone()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn hash(&self) -> H256 {
 | 
			
		||||
		BlockView::new(&self.encoded()).header_view().hash()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn number(&self) -> u64 {
 | 
			
		||||
		self.header.number()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn encoded(&self) -> Bytes {
 | 
			
		||||
		encode(self).into_vec()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct BlockOptions {
 | 
			
		||||
	pub difficulty: U256,
 | 
			
		||||
	pub bloom: Bloom,
 | 
			
		||||
	pub transactions: Vec<SignedTransaction>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for BlockOptions {
 | 
			
		||||
	fn default() -> Self {
 | 
			
		||||
		BlockOptions {
 | 
			
		||||
			difficulty: 10.into(),
 | 
			
		||||
			bloom: Bloom::default(),
 | 
			
		||||
			transactions: Vec::new(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct BlockBuilder {
 | 
			
		||||
	blocks: VecDeque<Block>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BlockBuilder {
 | 
			
		||||
	pub fn genesis() -> Self {
 | 
			
		||||
		let mut blocks = VecDeque::with_capacity(1);
 | 
			
		||||
		blocks.push_back(Block::default());
 | 
			
		||||
 | 
			
		||||
		BlockBuilder {
 | 
			
		||||
			blocks,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_block(&self) -> Self {
 | 
			
		||||
		self.add_block_with(|| BlockOptions::default())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_blocks(&self, count: usize) -> Self {
 | 
			
		||||
		self.add_blocks_with(count, || BlockOptions::default())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_block_with<T>(&self, get_metadata: T) -> Self where T: Fn() -> BlockOptions {
 | 
			
		||||
		self.add_blocks_with(1, get_metadata)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_block_with_difficulty<T>(&self, difficulty: T) -> Self where T: Into<U256> {
 | 
			
		||||
		let difficulty = difficulty.into();
 | 
			
		||||
		self.add_blocks_with(1, move || BlockOptions {
 | 
			
		||||
			difficulty,
 | 
			
		||||
			..Default::default()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_block_with_transactions<T>(&self, transactions: T) -> Self
 | 
			
		||||
		where T: IntoIterator<Item = SignedTransaction> {
 | 
			
		||||
		let transactions = transactions.into_iter().collect::<Vec<_>>();
 | 
			
		||||
		self.add_blocks_with(1, || BlockOptions {
 | 
			
		||||
			transactions: transactions.clone(),
 | 
			
		||||
			..Default::default()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn add_block_with_bloom(&self, bloom: Bloom) -> Self {
 | 
			
		||||
		self.add_blocks_with(1, move || BlockOptions {
 | 
			
		||||
			bloom,
 | 
			
		||||
			..Default::default()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pub fn add_blocks_with<T>(&self, count: usize, get_metadata: T) -> Self where T: Fn() -> BlockOptions {
 | 
			
		||||
		assert!(count > 0, "There must be at least 1 block");
 | 
			
		||||
		let mut parent_hash = self.last().hash();
 | 
			
		||||
		let mut parent_number = self.last().number();
 | 
			
		||||
		let mut blocks = VecDeque::with_capacity(count);
 | 
			
		||||
		for _ in 0..count {
 | 
			
		||||
			let mut block = Block::default();
 | 
			
		||||
			let metadata = get_metadata();
 | 
			
		||||
			let block_number = parent_number + 1;
 | 
			
		||||
			block.header.set_parent_hash(parent_hash);
 | 
			
		||||
			block.header.set_number(block_number);
 | 
			
		||||
			block.header.set_log_bloom(metadata.bloom);
 | 
			
		||||
			block.header.set_difficulty(metadata.difficulty);
 | 
			
		||||
			block.transactions = metadata.transactions;
 | 
			
		||||
 | 
			
		||||
			parent_hash = block.hash();
 | 
			
		||||
			parent_number = block_number;
 | 
			
		||||
 | 
			
		||||
			blocks.push_back(block);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		BlockBuilder {
 | 
			
		||||
			blocks,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	pub fn last(&self) -> &Block {
 | 
			
		||||
		self.blocks.back().expect("There is always at least 1 block")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct BlockGenerator {
 | 
			
		||||
	builders: VecDeque<BlockBuilder>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BlockGenerator {
 | 
			
		||||
	pub fn new<T>(builders: T) -> Self where T: IntoIterator<Item = BlockBuilder> {
 | 
			
		||||
		BlockGenerator {
 | 
			
		||||
			builders: builders.into_iter().collect(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Iterator for BlockGenerator {
 | 
			
		||||
	type Item = Block;
 | 
			
		||||
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		loop {
 | 
			
		||||
			match self.builders.front_mut() {
 | 
			
		||||
				Some(ref mut builder) => {
 | 
			
		||||
					if let Some(block) = builder.blocks.pop_front() {
 | 
			
		||||
						return Some(block);
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				None => return None,
 | 
			
		||||
			}
 | 
			
		||||
			self.builders.pop_front();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use super::{BlockBuilder, BlockOptions, BlockGenerator};
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn test_block_builder() {
 | 
			
		||||
		let genesis = BlockBuilder::genesis();
 | 
			
		||||
		let block_1 = genesis.add_block();
 | 
			
		||||
		let block_1001 = block_1.add_blocks(1000);
 | 
			
		||||
		let block_1002 = block_1001.add_block_with(|| BlockOptions::default());
 | 
			
		||||
		let generator = BlockGenerator::new(vec![genesis, block_1, block_1001, block_1002]);
 | 
			
		||||
		assert_eq!(generator.count(), 1003);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn test_block_builder_fork() {
 | 
			
		||||
		let genesis = BlockBuilder::genesis();
 | 
			
		||||
		let block_10a = genesis.add_blocks(10);
 | 
			
		||||
		let block_11b = genesis.add_blocks(11);
 | 
			
		||||
		assert_eq!(block_10a.last().number(), 10);
 | 
			
		||||
		assert_eq!(block_11b.last().number(), 11);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,72 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use rlp::*;
 | 
			
		||||
use ethereum_types::{H256, Bloom};
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use header::Header;
 | 
			
		||||
use transaction::SignedTransaction;
 | 
			
		||||
 | 
			
		||||
use super::fork::Forkable;
 | 
			
		||||
use super::bloom::WithBloom;
 | 
			
		||||
use super::complete::CompleteBlock;
 | 
			
		||||
use super::transaction::WithTransaction;
 | 
			
		||||
 | 
			
		||||
/// Helper structure, used for encoding blocks.
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct Block {
 | 
			
		||||
	pub header: Header,
 | 
			
		||||
	pub transactions: Vec<SignedTransaction>,
 | 
			
		||||
	pub uncles: Vec<Header>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Encodable for Block {
 | 
			
		||||
	fn rlp_append(&self, s: &mut RlpStream) {
 | 
			
		||||
		s.begin_list(3);
 | 
			
		||||
		s.append(&self.header);
 | 
			
		||||
		s.append_list(&self.transactions);
 | 
			
		||||
		s.append_list(&self.uncles);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Forkable for Block {
 | 
			
		||||
	fn fork(mut self, fork_number: usize) -> Self where Self: Sized {
 | 
			
		||||
		let difficulty = self.header.difficulty().clone() - fork_number.into();
 | 
			
		||||
		self.header.set_difficulty(difficulty);
 | 
			
		||||
		self
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WithBloom for Block {
 | 
			
		||||
	fn with_bloom(mut self, bloom: Bloom) -> Self where Self: Sized {
 | 
			
		||||
		self.header.set_log_bloom(bloom);
 | 
			
		||||
		self
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WithTransaction for Block {
 | 
			
		||||
	fn with_transaction(mut self, transaction: SignedTransaction) -> Self where Self: Sized {
 | 
			
		||||
		self.transactions.push(transaction);
 | 
			
		||||
		self
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CompleteBlock for Block {
 | 
			
		||||
	fn complete(mut self, parent_hash: H256) -> Bytes {
 | 
			
		||||
		self.header.set_parent_hash(parent_hash);
 | 
			
		||||
		encode(&self).into_vec()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use ethereum_types::Bloom as LogBloom;
 | 
			
		||||
 | 
			
		||||
pub trait WithBloom {
 | 
			
		||||
	fn with_bloom(self, bloom: LogBloom) -> Self where Self: Sized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Bloom<'a, I> where I: 'a {
 | 
			
		||||
	pub iter: &'a mut I,
 | 
			
		||||
	pub bloom: LogBloom,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, I> Iterator for Bloom<'a, I> where I: Iterator, <I as Iterator>::Item: WithBloom {
 | 
			
		||||
	type Item = <I as Iterator>::Item;
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		self.iter.next().map(|item| item.with_bloom(self.bloom.clone()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,52 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use ethereum_types::H256;
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use views::BlockView;
 | 
			
		||||
 | 
			
		||||
#[derive(Default, Clone)]
 | 
			
		||||
pub struct BlockFinalizer {
 | 
			
		||||
	parent_hash: H256
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl BlockFinalizer {
 | 
			
		||||
	pub fn fork(&self) -> Self {
 | 
			
		||||
		self.clone()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait CompleteBlock {
 | 
			
		||||
	fn complete(self, parent_hash: H256) -> Bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Complete<'a, I> where I: 'a {
 | 
			
		||||
	pub iter: &'a mut I,
 | 
			
		||||
	pub finalizer: &'a mut BlockFinalizer,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, I> Iterator for Complete<'a, I> where I: Iterator, <I as Iterator>::Item: CompleteBlock {
 | 
			
		||||
	type Item = Bytes;
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		self.iter.next().map(|item| {
 | 
			
		||||
			let rlp = item.complete(self.finalizer.parent_hash.clone());
 | 
			
		||||
			self.finalizer.parent_hash = BlockView::new(&rlp).header_view().hash();
 | 
			
		||||
			rlp
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,42 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
pub trait Forkable {
 | 
			
		||||
	fn fork(self, fork_number: usize) -> Self where Self: Sized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Fork<I> {
 | 
			
		||||
	pub iter: I,
 | 
			
		||||
	pub fork_number: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<I> Clone for Fork<I> where I: Iterator + Clone {
 | 
			
		||||
	fn clone(&self) -> Self {
 | 
			
		||||
		Fork {
 | 
			
		||||
			iter: self.iter.clone(),
 | 
			
		||||
			fork_number: self.fork_number
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<I> Iterator for Fork<I> where I: Iterator, <I as Iterator>::Item: Forkable {
 | 
			
		||||
	type Item = <I as Iterator>::Item;
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		self.iter.next().map(|item| item.fork(self.fork_number))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,178 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use ethereum_types::{Bloom as LogBloom, U256};
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use header::BlockNumber;
 | 
			
		||||
use transaction::SignedTransaction;
 | 
			
		||||
use super::fork::Fork;
 | 
			
		||||
use super::bloom::Bloom;
 | 
			
		||||
use super::complete::{BlockFinalizer, CompleteBlock, Complete};
 | 
			
		||||
use super::block::Block;
 | 
			
		||||
use super::transaction::Transaction;
 | 
			
		||||
 | 
			
		||||
/// Chain iterator interface.
 | 
			
		||||
pub trait ChainIterator: Iterator + Sized {
 | 
			
		||||
	/// Should be called to create a fork of current iterator.
 | 
			
		||||
	/// Blocks generated by fork will have lower difficulty than current chain.
 | 
			
		||||
	fn fork(&self, fork_number: usize) -> Fork<Self> where Self: Clone;
 | 
			
		||||
	/// Should be called to make every consecutive block have given bloom.
 | 
			
		||||
	fn with_bloom(&mut self, bloom: LogBloom) -> Bloom<Self>;
 | 
			
		||||
	/// Should be called to make every consecutive block have given transaction.
 | 
			
		||||
	fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction<Self>;
 | 
			
		||||
	/// Should be called to complete block. Without complete, block may have incorrect hash.
 | 
			
		||||
	fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self>;
 | 
			
		||||
	/// Completes and generates block.
 | 
			
		||||
	fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option<Bytes> where Self::Item: CompleteBlock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<I> ChainIterator for I where I: Iterator + Sized {
 | 
			
		||||
	fn fork(&self, fork_number: usize) -> Fork<Self> where I: Clone {
 | 
			
		||||
		Fork {
 | 
			
		||||
			iter: self.clone(),
 | 
			
		||||
			fork_number: fork_number
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn with_bloom(&mut self, bloom: LogBloom) -> Bloom<Self> {
 | 
			
		||||
		Bloom {
 | 
			
		||||
			iter: self,
 | 
			
		||||
			bloom: bloom
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction<Self> {
 | 
			
		||||
		Transaction {
 | 
			
		||||
			iter: self,
 | 
			
		||||
			transaction: transaction,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn complete<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Complete<'a, Self> {
 | 
			
		||||
		Complete {
 | 
			
		||||
			iter: self,
 | 
			
		||||
			finalizer: finalizer
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn generate<'a>(&'a mut self, finalizer: &'a mut BlockFinalizer) -> Option<Bytes> where <I as Iterator>::Item: CompleteBlock {
 | 
			
		||||
		self.complete(finalizer).next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Blockchain generator.
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct ChainGenerator {
 | 
			
		||||
	/// Next block number.
 | 
			
		||||
	number: BlockNumber,
 | 
			
		||||
	/// Next block difficulty.
 | 
			
		||||
	difficulty: U256,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ChainGenerator {
 | 
			
		||||
	fn prepare_block(&self) -> Block {
 | 
			
		||||
		let mut block = Block::default();
 | 
			
		||||
		block.header.set_number(self.number);
 | 
			
		||||
		block.header.set_difficulty(self.difficulty);
 | 
			
		||||
		block
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for ChainGenerator {
 | 
			
		||||
	fn default() -> Self {
 | 
			
		||||
		ChainGenerator {
 | 
			
		||||
			number: 0,
 | 
			
		||||
			difficulty: 1000.into(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Iterator for ChainGenerator {
 | 
			
		||||
	type Item = Block;
 | 
			
		||||
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		let block = self.prepare_block();
 | 
			
		||||
		self.number += 1;
 | 
			
		||||
		Some(block)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod tests {
 | 
			
		||||
	use ethereum_types::{H256, Bloom as LogBloom};
 | 
			
		||||
	use views::BlockView;
 | 
			
		||||
	use blockchain::generator::{ChainIterator, ChainGenerator, BlockFinalizer};
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn canon_chain_generator() {
 | 
			
		||||
		let mut canon_chain = ChainGenerator::default();
 | 
			
		||||
		let mut finalizer = BlockFinalizer::default();
 | 
			
		||||
 | 
			
		||||
		let genesis_rlp = canon_chain.generate(&mut finalizer).unwrap();
 | 
			
		||||
		let genesis = BlockView::new(&genesis_rlp);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(genesis.header_view().parent_hash(), H256::default());
 | 
			
		||||
		assert_eq!(genesis.header_view().number(), 0);
 | 
			
		||||
 | 
			
		||||
		let b1_rlp = canon_chain.generate(&mut finalizer).unwrap();
 | 
			
		||||
		let b1 = BlockView::new(&b1_rlp);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(b1.header_view().parent_hash(), genesis.header_view().hash());
 | 
			
		||||
		assert_eq!(b1.header_view().number(), 1);
 | 
			
		||||
 | 
			
		||||
		let mut fork_chain = canon_chain.fork(1);
 | 
			
		||||
 | 
			
		||||
		let b2_rlp_fork = fork_chain.generate(&mut finalizer.fork()).unwrap();
 | 
			
		||||
		let b2_fork = BlockView::new(&b2_rlp_fork);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().hash());
 | 
			
		||||
		assert_eq!(b2_fork.header_view().number(), 2);
 | 
			
		||||
 | 
			
		||||
		let b2_rlp = canon_chain.generate(&mut finalizer).unwrap();
 | 
			
		||||
		let b2 = BlockView::new(&b2_rlp);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(b2.header_view().parent_hash(), b1.header_view().hash());
 | 
			
		||||
		assert_eq!(b2.header_view().number(), 2);
 | 
			
		||||
		assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn with_bloom_generator() {
 | 
			
		||||
		let bloom = LogBloom([0x1; 256]);
 | 
			
		||||
		let mut gen = ChainGenerator::default();
 | 
			
		||||
		let mut finalizer = BlockFinalizer::default();
 | 
			
		||||
 | 
			
		||||
		let block0_rlp = gen.with_bloom(bloom).generate(&mut finalizer).unwrap();
 | 
			
		||||
		let block1_rlp = gen.generate(&mut finalizer).unwrap();
 | 
			
		||||
		let block0 = BlockView::new(&block0_rlp);
 | 
			
		||||
		let block1 = BlockView::new(&block1_rlp);
 | 
			
		||||
 | 
			
		||||
		assert_eq!(block0.header_view().number(), 0);
 | 
			
		||||
		assert_eq!(block0.header_view().parent_hash(), H256::default());
 | 
			
		||||
 | 
			
		||||
		assert_eq!(block1.header_view().number(), 1);
 | 
			
		||||
		assert_eq!(block1.header_view().parent_hash(), block0.header_view().hash());
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn generate_1000_blocks() {
 | 
			
		||||
		let generator = ChainGenerator::default();
 | 
			
		||||
		let mut finalizer = BlockFinalizer::default();
 | 
			
		||||
		let blocks: Vec<_> = generator.take(1000).complete(&mut finalizer).collect();
 | 
			
		||||
		assert_eq!(blocks.len(), 1000);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,27 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! Blockchain generator for tests.
 | 
			
		||||
 | 
			
		||||
mod bloom;
 | 
			
		||||
mod block;
 | 
			
		||||
mod complete;
 | 
			
		||||
mod fork;
 | 
			
		||||
pub mod generator;
 | 
			
		||||
mod transaction;
 | 
			
		||||
 | 
			
		||||
pub use self::complete::BlockFinalizer;
 | 
			
		||||
pub use self::generator::{ChainIterator, ChainGenerator};
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use transaction::SignedTransaction;
 | 
			
		||||
 | 
			
		||||
pub trait WithTransaction {
 | 
			
		||||
	fn with_transaction(self, transaction: SignedTransaction) -> Self where Self: Sized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Transaction<'a, I> where I: 'a {
 | 
			
		||||
	pub iter: &'a mut I,
 | 
			
		||||
	pub transaction: SignedTransaction,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl <'a, I> Iterator for Transaction<'a, I> where I: Iterator, <I as Iterator>::Item: WithTransaction {
 | 
			
		||||
	type Item = <I as Iterator>::Item;
 | 
			
		||||
 | 
			
		||||
	#[inline]
 | 
			
		||||
	fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
		self.iter.next().map(|item| item.with_transaction(self.transaction.clone()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -21,7 +21,7 @@ use std::sync::atomic::AtomicBool;
 | 
			
		||||
use tempdir::TempDir;
 | 
			
		||||
use error::Error;
 | 
			
		||||
 | 
			
		||||
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
 | 
			
		||||
use blockchain::generator::{BlockGenerator, BlockBuilder};
 | 
			
		||||
use blockchain::BlockChain;
 | 
			
		||||
use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents};
 | 
			
		||||
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
 | 
			
		||||
@ -34,22 +34,22 @@ use kvdb_memorydb;
 | 
			
		||||
const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot { blocks: 30000, max_restore_blocks: 30000 };
 | 
			
		||||
 | 
			
		||||
fn chunk_and_restore(amount: u64) {
 | 
			
		||||
	let mut canon_chain = ChainGenerator::default();
 | 
			
		||||
	let mut finalizer = BlockFinalizer::default();
 | 
			
		||||
	let genesis = canon_chain.generate(&mut finalizer).unwrap();
 | 
			
		||||
	let genesis = BlockBuilder::genesis();
 | 
			
		||||
	let rest = genesis.add_blocks(amount as usize);
 | 
			
		||||
	let generator = BlockGenerator::new(vec![rest]);
 | 
			
		||||
	let genesis = genesis.last();
 | 
			
		||||
 | 
			
		||||
	let engine = ::spec::Spec::new_test().engine;
 | 
			
		||||
	let tempdir = TempDir::new("").unwrap();
 | 
			
		||||
	let snapshot_path = tempdir.path().join("SNAP");
 | 
			
		||||
 | 
			
		||||
	let old_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
 | 
			
		||||
	let bc = BlockChain::new(Default::default(), &genesis, old_db.clone());
 | 
			
		||||
	let bc = BlockChain::new(Default::default(), &genesis.encoded(), old_db.clone());
 | 
			
		||||
 | 
			
		||||
	// build the blockchain.
 | 
			
		||||
	let mut batch = DBTransaction::new();
 | 
			
		||||
	for _ in 0..amount {
 | 
			
		||||
		let block = canon_chain.generate(&mut finalizer).unwrap();
 | 
			
		||||
		bc.insert_block(&mut batch, &block, vec![]);
 | 
			
		||||
	for block in generator {
 | 
			
		||||
		bc.insert_block(&mut batch, &block.encoded(), vec![]);
 | 
			
		||||
		bc.commit();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -80,7 +80,7 @@ fn chunk_and_restore(amount: u64) {
 | 
			
		||||
 | 
			
		||||
	// restore it.
 | 
			
		||||
	let new_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
 | 
			
		||||
	let new_chain = BlockChain::new(Default::default(), &genesis, new_db.clone());
 | 
			
		||||
	let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db.clone());
 | 
			
		||||
	let mut rebuilder = SNAPSHOT_MODE.rebuilder(new_chain, new_db.clone(), &manifest).unwrap();
 | 
			
		||||
 | 
			
		||||
	let reader = PackedReader::new(&snapshot_path).unwrap().unwrap();
 | 
			
		||||
@ -95,15 +95,19 @@ fn chunk_and_restore(amount: u64) {
 | 
			
		||||
	drop(rebuilder);
 | 
			
		||||
 | 
			
		||||
	// and test it.
 | 
			
		||||
	let new_chain = BlockChain::new(Default::default(), &genesis, new_db);
 | 
			
		||||
	let new_chain = BlockChain::new(Default::default(), &genesis.encoded(), new_db);
 | 
			
		||||
	assert_eq!(new_chain.best_block_hash(), best_hash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn chunk_and_restore_500() { chunk_and_restore(500) }
 | 
			
		||||
fn chunk_and_restore_500() {
 | 
			
		||||
	chunk_and_restore(500)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn chunk_and_restore_40k() { chunk_and_restore(40000) }
 | 
			
		||||
fn chunk_and_restore_4k() {
 | 
			
		||||
	chunk_and_restore(4000)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn checks_flag() {
 | 
			
		||||
@ -118,17 +122,12 @@ fn checks_flag() {
 | 
			
		||||
 | 
			
		||||
	stream.append_empty_data().append_empty_data();
 | 
			
		||||
 | 
			
		||||
	let genesis = {
 | 
			
		||||
		let mut canon_chain = ChainGenerator::default();
 | 
			
		||||
		let mut finalizer = BlockFinalizer::default();
 | 
			
		||||
		canon_chain.generate(&mut finalizer).unwrap()
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	let genesis = BlockBuilder::genesis();
 | 
			
		||||
	let chunk = stream.out();
 | 
			
		||||
 | 
			
		||||
	let db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
 | 
			
		||||
	let engine = ::spec::Spec::new_test().engine;
 | 
			
		||||
	let chain = BlockChain::new(Default::default(), &genesis, db.clone());
 | 
			
		||||
	let chain = BlockChain::new(Default::default(), &genesis.last().encoded(), db.clone());
 | 
			
		||||
 | 
			
		||||
	let manifest = ::snapshot::ManifestData {
 | 
			
		||||
		version: 2,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user