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 tempdir::TempDir;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer};
|
use blockchain::generator::{BlockGenerator, BlockBuilder};
|
||||||
use blockchain::BlockChain;
|
use blockchain::BlockChain;
|
||||||
use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents};
|
use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents};
|
||||||
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
|
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 };
|
const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot { blocks: 30000, max_restore_blocks: 30000 };
|
||||||
|
|
||||||
fn chunk_and_restore(amount: u64) {
|
fn chunk_and_restore(amount: u64) {
|
||||||
let mut canon_chain = ChainGenerator::default();
|
let genesis = BlockBuilder::genesis();
|
||||||
let mut finalizer = BlockFinalizer::default();
|
let rest = genesis.add_blocks(amount as usize);
|
||||||
let genesis = canon_chain.generate(&mut finalizer).unwrap();
|
let generator = BlockGenerator::new(vec![rest]);
|
||||||
|
let genesis = genesis.last();
|
||||||
|
|
||||||
let engine = ::spec::Spec::new_test().engine;
|
let engine = ::spec::Spec::new_test().engine;
|
||||||
let tempdir = TempDir::new("").unwrap();
|
let tempdir = TempDir::new("").unwrap();
|
||||||
let snapshot_path = tempdir.path().join("SNAP");
|
let snapshot_path = tempdir.path().join("SNAP");
|
||||||
|
|
||||||
let old_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
|
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.
|
// build the blockchain.
|
||||||
let mut batch = DBTransaction::new();
|
let mut batch = DBTransaction::new();
|
||||||
for _ in 0..amount {
|
for block in generator {
|
||||||
let block = canon_chain.generate(&mut finalizer).unwrap();
|
bc.insert_block(&mut batch, &block.encoded(), vec![]);
|
||||||
bc.insert_block(&mut batch, &block, vec![]);
|
|
||||||
bc.commit();
|
bc.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
|
|
||||||
// restore it.
|
// restore it.
|
||||||
let new_db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
|
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 mut rebuilder = SNAPSHOT_MODE.rebuilder(new_chain, new_db.clone(), &manifest).unwrap();
|
||||||
|
|
||||||
let reader = PackedReader::new(&snapshot_path).unwrap().unwrap();
|
let reader = PackedReader::new(&snapshot_path).unwrap().unwrap();
|
||||||
@ -95,15 +95,19 @@ fn chunk_and_restore(amount: u64) {
|
|||||||
drop(rebuilder);
|
drop(rebuilder);
|
||||||
|
|
||||||
// and test it.
|
// 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);
|
assert_eq!(new_chain.best_block_hash(), best_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn chunk_and_restore_500() { chunk_and_restore(500) }
|
fn chunk_and_restore_500() {
|
||||||
|
chunk_and_restore(500)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn chunk_and_restore_40k() { chunk_and_restore(40000) }
|
fn chunk_and_restore_4k() {
|
||||||
|
chunk_and_restore(4000)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn checks_flag() {
|
fn checks_flag() {
|
||||||
@ -118,17 +122,12 @@ fn checks_flag() {
|
|||||||
|
|
||||||
stream.append_empty_data().append_empty_data();
|
stream.append_empty_data().append_empty_data();
|
||||||
|
|
||||||
let genesis = {
|
let genesis = BlockBuilder::genesis();
|
||||||
let mut canon_chain = ChainGenerator::default();
|
|
||||||
let mut finalizer = BlockFinalizer::default();
|
|
||||||
canon_chain.generate(&mut finalizer).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let chunk = stream.out();
|
let chunk = stream.out();
|
||||||
|
|
||||||
let db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
|
let db = Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0)));
|
||||||
let engine = ::spec::Spec::new_test().engine;
|
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 {
|
let manifest = ::snapshot::ManifestData {
|
||||||
version: 2,
|
version: 2,
|
||||||
|
Loading…
Reference in New Issue
Block a user