// Copyright 2015-2020 Parity Technologies (UK) Ltd. // This file is part of OpenEthereum. // OpenEthereum 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. // OpenEthereum 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 OpenEthereum. If not, see . //! Blockchain generator for tests. use ethereum_types::{Bloom, H256, U256}; use std::collections::VecDeque; use common_types::{ encoded, header::Header, transaction::{Action, SignedTransaction, Transaction}, view, views::BlockView, }; use keccak_hash::keccak; use rlp::encode; use rlp_derive::RlpEncodable; use triehash_ethereum::ordered_trie_root; /// Helper structure, used for encoding blocks. #[derive(Default, Clone, RlpEncodable)] pub struct Block { /// Block header pub header: Header, /// Block transactions pub transactions: Vec, /// Block uncles pub uncles: Vec
, } impl Block { /// Get a copy of the header #[inline] pub fn header(&self) -> Header { self.header.clone() } /// Get block hash #[inline] pub fn hash(&self) -> H256 { view!(BlockView, &self.encoded().raw()).header_view().hash() } /// Get block number #[inline] pub fn number(&self) -> u64 { self.header.number() } /// Get RLP encoding of this block #[inline] pub fn encoded(&self) -> encoded::Block { encoded::Block::new(encode(self)) } /// Get block difficulty #[inline] pub fn difficulty(&self) -> U256 { *self.header.difficulty() } } /// Specify block options for generator #[derive(Debug)] pub struct BlockOptions { /// Difficulty pub difficulty: U256, /// Set bloom filter pub bloom: Bloom, /// Transactions included in blocks pub transactions: Vec, } impl Default for BlockOptions { fn default() -> Self { BlockOptions { difficulty: 10.into(), bloom: Bloom::default(), transactions: Vec::new(), } } } /// Utility to create blocks #[derive(Clone)] pub struct BlockBuilder { blocks: VecDeque, } impl BlockBuilder { /// Create new BlockBuilder starting at genesis. pub fn genesis() -> Self { let mut blocks = VecDeque::with_capacity(1); blocks.push_back(Block::default()); BlockBuilder { blocks } } /// Add new block with default options. #[inline] pub fn add_block(&self) -> Self { self.add_block_with(|| BlockOptions::default()) } /// Add `count` number of blocks with default options. #[inline] pub fn add_blocks(&self, count: usize) -> Self { self.add_blocks_with(count, || BlockOptions::default()) } /// Add block with specified options. #[inline] pub fn add_block_with(&self, get_metadata: T) -> Self where T: Fn() -> BlockOptions, { self.add_blocks_with(1, get_metadata) } /// Add a block with given difficulty #[inline] pub fn add_block_with_difficulty(&self, difficulty: T) -> Self where T: Into, { let difficulty = difficulty.into(); self.add_blocks_with(1, move || BlockOptions { difficulty, ..Default::default() }) } /// Add a block with randomly generated transactions. #[inline] pub fn add_block_with_random_transactions(&self) -> Self { // Maximum of ~50 transactions let count = rand::random::() as usize / 5; let transactions = std::iter::repeat_with(|| { let data_len = rand::random::(); let data = std::iter::repeat_with(|| rand::random::()) .take(data_len as usize) .collect::>(); Transaction { nonce: 0.into(), gas_price: 0.into(), gas: 100_000.into(), action: Action::Create, value: 100.into(), data, } .sign(&keccak("").into(), None) }) .take(count); self.add_block_with_transactions(transactions) } /// Add a block with given transactions. #[inline] pub fn add_block_with_transactions(&self, transactions: T) -> Self where T: IntoIterator, { let transactions = transactions.into_iter().collect::>(); self.add_blocks_with(1, || BlockOptions { transactions: transactions.clone(), ..Default::default() }) } /// Add a block with given bloom filter. #[inline] pub fn add_block_with_bloom(&self, bloom: Bloom) -> Self { self.add_blocks_with(1, move || BlockOptions { bloom, ..Default::default() }) } /// Add a bunch of blocks with given metadata. pub fn add_blocks_with(&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; let transactions = metadata.transactions; let transactions_root = ordered_trie_root(transactions.iter().map(rlp::encode)); 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.header.set_transactions_root(transactions_root); block.transactions = transactions; parent_hash = block.hash(); parent_number = block_number; blocks.push_back(block); } BlockBuilder { blocks } } /// Get a reference to the last generated block. #[inline] pub fn last(&self) -> &Block { self.blocks .back() .expect("There is always at least 1 block") } } /// Generates a blockchain from given block builders (blocks will be concatenated). #[derive(Clone)] pub struct BlockGenerator { builders: VecDeque, } impl BlockGenerator { /// Create new block generator. pub fn new(builders: T) -> Self where T: IntoIterator, { BlockGenerator { builders: builders.into_iter().collect(), } } } impl Iterator for BlockGenerator { type Item = Block; fn next(&mut self) -> Option { 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, BlockGenerator, BlockOptions}; #[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); } }