From ab9fddf6b2e4d00e4961d98bb418679af5325e4e Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 1 Mar 2016 13:44:09 +0100 Subject: [PATCH] blockchain generator --- ethcore/src/blockchain/blockchain.rs | 41 +++--- ethcore/src/blockchain/helpers/generators.rs | 138 +++++++++++++++++++ ethcore/src/blockchain/helpers/mod.rs | 3 + ethcore/src/blockchain/mod.rs | 2 + 4 files changed, 165 insertions(+), 19 deletions(-) create mode 100644 ethcore/src/blockchain/helpers/generators.rs create mode 100644 ethcore/src/blockchain/helpers/mod.rs diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8aa0fffdc..cc95b4f3b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -447,7 +447,7 @@ impl BlockChain { let mut write_details = self.block_details.write().unwrap(); for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); + batch.put_extras(&hash, &details); write_details.insert(hash, details); } @@ -572,7 +572,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); - let transaction_hashes = block.transaction_hashes(); + let transaction_hashes = block.transaction_hashes(); transaction_hashes.into_iter() .enumerate() @@ -587,20 +587,20 @@ impl BlockChain { /// This functions returns modified blocks blooms. /// - /// To accelerate blooms lookups, blomms are stored in multiple - /// layers (BLOOM_LEVELS, currently 3). + /// To accelerate blooms lookups, blomms are stored in multiple + /// layers (BLOOM_LEVELS, currently 3). /// ChainFilter is responsible for building and rebuilding these layers. /// It returns them in HashMap, where values are Blooms and /// keys are BloomIndexes. BloomIndex represents bloom location on one /// of these layers. - /// + /// /// To reduce number of queries to databse, block blooms are stored - /// in BlocksBlooms structure which contains info about several + /// in BlocksBlooms structure which contains info about several /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms. - /// + /// /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) /// to bloom location in database (BlocksBloomLocation). - /// + /// fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); let header = block.header_view(); @@ -766,32 +766,33 @@ mod tests { use std::str::FromStr; use rustc_serialize::hex::FromHex; use util::hash::*; + use util::sha3::Hashable; use blockchain::{BlockProvider, BlockChain, BlockChainConfig}; use tests::helpers::*; use devtools::*; + use blockchain::helpers::generators::ChainGenerator; + use views::BlockView; #[test] - fn valid_tests_extra32() { - let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap(); + fn basic_blockchain_insert() { + let mut canon_chain = ChainGenerator::default(); + let genesis = canon_chain.next().unwrap(); + let first = canon_chain.next().unwrap(); + let genesis_hash = BlockView::new(&genesis).header_view().sha3(); + let first_hash = BlockView::new(&first).header_view().sha3(); let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); - let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap(); - assert_eq!(bc.genesis_hash(), genesis_hash.clone()); assert_eq!(bc.best_block_number(), 0); assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); - - let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); bc.insert_block(&first, vec![]); - let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap(); - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.best_block_number(), 1); assert_eq!(bc.best_block_hash(), first_hash.clone()); @@ -961,7 +962,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path()); bc.insert_block(&b1, vec![]); - + let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { @@ -981,7 +982,7 @@ mod tests { // prepare for fork (b1a, child of genesis) let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); - + // fork (b2a, child of b1a, with higher total difficulty) let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap(); @@ -1001,7 +1002,7 @@ mod tests { let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![]); assert_eq!(blocks_b2, vec![]); - + bc.insert_block(&b1, vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); @@ -1043,4 +1044,6 @@ mod tests { } + + } diff --git a/ethcore/src/blockchain/helpers/generators.rs b/ethcore/src/blockchain/helpers/generators.rs new file mode 100644 index 000000000..8416a07ad --- /dev/null +++ b/ethcore/src/blockchain/helpers/generators.rs @@ -0,0 +1,138 @@ +use util::rlp::*; +use util::hash::{H256, H2048}; +use util::uint::{U256}; +use util::bytes::Bytes; +use header::{BlockNumber, Header}; +use transaction::SignedTransaction; + +/// Chain iterator interface. +pub trait ChainIterator: Iterator { + /// Should be called to create a fork of current iterator. + /// Blocks generated by fork will have lower difficulty than current chain. + fn fork(&mut self) -> Self; + /// Should be called to create new block with given bloom. + fn next_with_bloom(&mut self, bloom: H2048) -> Option; +} + +/// Helper structure, used for encoding blocks. +#[derive(Default)] +struct Block { + header: Header, + transactions: Vec, + uncles: Vec
+} + +impl Encodable for Block { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(3); + s.append(&self.header); + s.append(&self.transactions); + s.append(&self.uncles); + } +} + +/// Blockchain generator. +pub struct ChainGenerator { + /// Next block number. + number: BlockNumber, + /// Next block parent hash. + parent_hash: H256, + /// Next block difficulty. + difficulty: U256, + /// Number of forks of current block. + number_of_forks: usize, +} + +impl ChainGenerator { + fn prepare_block(&self) -> Block { + let mut block = Block::default(); + block.header.parent_hash = self.parent_hash.clone(); + block.header.number = self.number; + block.header.difficulty = self.difficulty; + block + } +} + +impl Default for ChainGenerator { + fn default() -> Self { + ChainGenerator { + number: 0, + parent_hash: H256::default(), + difficulty: U256::from(1000), + number_of_forks: 0 + } + } +} + +impl Iterator for ChainGenerator { + type Item = Bytes; + + fn next(&mut self) -> Option { + let block = self.prepare_block(); + self.number += 1; + self.parent_hash = block.header.hash(); + self.number_of_forks = 0; + Some(encode(&block).to_vec()) + } +} + +impl ChainIterator for ChainGenerator { + fn fork(&mut self) -> Self { + self.number_of_forks += 1; + ChainGenerator { + number: self.number, + parent_hash: self.parent_hash.clone(), + difficulty: self.difficulty - U256::from(self.number_of_forks), + number_of_forks: 0 + } + } + + fn next_with_bloom(&mut self, bloom: H2048) -> Option { + let mut block = self.prepare_block(); + block.header.log_bloom = bloom; + self.number += 1; + self.parent_hash = block.header.hash(); + self.number_of_forks = 0; + Some(encode(&block).to_vec()) + } +} + +#[cfg(test)] +mod tests { + use util::hash::H256; + use util::sha3::Hashable; + use views::BlockView; + use super::{ChainIterator, ChainGenerator}; + + #[test] + fn canon_chain_generator() { + let mut canon_chain = ChainGenerator::default(); + + let genesis_rlp = canon_chain.next().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.next().unwrap(); + let b1 = BlockView::new(&b1_rlp); + + assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3()); + assert_eq!(b1.header_view().number(), 1); + + let mut fork_chain = canon_chain.fork(); + + let b2_rlp_fork = fork_chain.next().unwrap(); + let b2_fork = BlockView::new(&b2_rlp_fork); + + assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2_fork.header_view().number(), 2); + + let b2_rlp = canon_chain.next().unwrap(); + let b2 = BlockView::new(&b2_rlp); + + assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3()); + assert_eq!(b2.header_view().number(), 2); + assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty()); + } +} diff --git a/ethcore/src/blockchain/helpers/mod.rs b/ethcore/src/blockchain/helpers/mod.rs new file mode 100644 index 000000000..0240bd00f --- /dev/null +++ b/ethcore/src/blockchain/helpers/mod.rs @@ -0,0 +1,3 @@ +pub mod generators; + +//pub use self::blockchain_builder::BlockChainBuilder; diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index c1046d960..60a1aeb33 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -23,6 +23,8 @@ mod bloom_indexer; mod cache; mod tree_route; mod update; +#[cfg(test)] +mod helpers; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize;