From c6b931766c032589499d7342ed318936234fc368 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 16 Feb 2018 10:11:29 +0100 Subject: [PATCH] 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 --- ethcore/src/blockchain/blockchain.rs | 562 ++++++++---------- ethcore/src/blockchain/generator.rs | 218 +++++++ ethcore/src/blockchain/generator/block.rs | 72 --- ethcore/src/blockchain/generator/bloom.rs | 35 -- ethcore/src/blockchain/generator/complete.rs | 52 -- ethcore/src/blockchain/generator/fork.rs | 42 -- ethcore/src/blockchain/generator/generator.rs | 178 ------ ethcore/src/blockchain/generator/mod.rs | 27 - .../src/blockchain/generator/transaction.rs | 35 -- ethcore/src/snapshot/tests/proof_of_work.rs | 37 +- 10 files changed, 493 insertions(+), 765 deletions(-) create mode 100644 ethcore/src/blockchain/generator.rs delete mode 100644 ethcore/src/blockchain/generator/block.rs delete mode 100644 ethcore/src/blockchain/generator/bloom.rs delete mode 100644 ethcore/src/blockchain/generator/complete.rs delete mode 100644 ethcore/src/blockchain/generator/fork.rs delete mode 100644 ethcore/src/blockchain/generator/generator.rs delete mode 100644 ethcore/src/blockchain/generator/mod.rs delete mode 100644 ethcore/src/blockchain/generator/transaction.rs diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 81b79bf9f..9013b2d01 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -228,7 +228,7 @@ impl BlockProvider for BlockChain { } fn best_ancient_block(&self) -> Option { - self.best_ancient_block.read().as_ref().map(|b| b.hash.clone()) + self.best_ancient_block.read().as_ref().map(|b| b.hash) } fn best_ancient_number(&self) -> Option { @@ -278,13 +278,13 @@ impl BlockProvider for BlockChain { Some(b) => { let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).into_vec(); let mut write = self.block_headers.write(); - write.insert(hash.clone(), bytes.clone()); + write.insert(*hash, bytes.clone()); Some(encoded::Header::new(bytes)) }, None => None }; - self.cache_man.lock().note_used(CacheId::BlockHeader(hash.clone())); + self.cache_man.lock().note_used(CacheId::BlockHeader(*hash)); result } @@ -314,13 +314,13 @@ impl BlockProvider for BlockChain { Some(b) => { let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).into_vec(); let mut write = self.block_bodies.write(); - write.insert(hash.clone(), bytes.clone()); + write.insert(*hash, bytes.clone()); Some(encoded::Body::new(bytes)) }, None => None }; - self.cache_man.lock().note_used(CacheId::BlockBody(hash.clone())); + self.cache_man.lock().note_used(CacheId::BlockBody(*hash)); result } @@ -328,7 +328,7 @@ impl BlockProvider for BlockChain { /// Get the familial details concerning a block. fn block_details(&self, hash: &H256) -> Option { let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_details, hash); - self.cache_man.lock().note_used(CacheId::BlockDetails(hash.clone())); + self.cache_man.lock().note_used(CacheId::BlockDetails(*hash)); result } @@ -342,14 +342,14 @@ impl BlockProvider for BlockChain { /// Get the address of transaction with given hash. fn transaction_address(&self, hash: &H256) -> Option { let result = self.db.read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash); - self.cache_man.lock().note_used(CacheId::TransactionAddresses(hash.clone())); + self.cache_man.lock().note_used(CacheId::TransactionAddresses(*hash)); result } /// Get receipts of block with given hash. fn block_receipts(&self, hash: &H256) -> Option { let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_receipts, hash); - self.cache_man.lock().note_used(CacheId::BlockReceipts(hash.clone())); + self.cache_man.lock().note_used(CacheId::BlockReceipts(*hash)); result } @@ -796,7 +796,7 @@ impl BlockChain { if let Some(parent_details) = maybe_parent { // parent known to be in chain. let info = BlockInfo { - hash: hash.clone(), + hash: hash, number: header.number(), total_difficulty: parent_details.total_difficulty + header.difficulty(), location: BlockLocation::CanonChain, @@ -1197,7 +1197,7 @@ impl BlockChain { match info.location { BlockLocation::Branch => (), BlockLocation::CanonChain => { - block_hashes.insert(number, info.hash.clone()); + block_hashes.insert(number, info.hash); }, BlockLocation::BranchBecomingCanonChain(ref data) => { let ancestor_number = self.block_number(&data.ancestor).expect("Block number of ancestor is always in DB"); @@ -1207,7 +1207,7 @@ impl BlockChain { block_hashes.insert(start_number + index as BlockNumber, hash); } - block_hashes.insert(number, info.hash.clone()); + block_hashes.insert(number, info.hash); } } @@ -1223,27 +1223,27 @@ impl BlockChain { // update parent let mut parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - parent_details.children.push(info.hash.clone()); + parent_details.children.push(info.hash); // create current block details. let details = BlockDetails { number: header.number(), total_difficulty: info.total_difficulty, - parent: parent_hash.clone(), + parent: parent_hash, children: vec![], }; // write to batch let mut block_details = HashMap::new(); block_details.insert(parent_hash, parent_details); - block_details.insert(info.hash.clone(), details); + block_details.insert(info.hash, details); block_details } /// This function returns modified block receipts. fn prepare_block_receipts_update(&self, receipts: Vec, info: &BlockInfo) -> HashMap { let mut block_receipts = HashMap::new(); - block_receipts.insert(info.hash.clone(), BlockReceipts::new(receipts)); + block_receipts.insert(info.hash, BlockReceipts::new(receipts)); block_receipts } @@ -1258,7 +1258,7 @@ impl BlockChain { .enumerate() .map(|(i ,tx_hash)| { (tx_hash, Some(TransactionAddress { - block_hash: info.hash.clone(), + block_hash: info.hash, index: i })) }) @@ -1272,7 +1272,7 @@ impl BlockChain { hashes.into_iter() .enumerate() .map(|(i, tx_hash)| (tx_hash, Some(TransactionAddress { - block_hash: hash.clone(), + block_hash: *hash, index: i, }))) .collect::>>() @@ -1282,7 +1282,7 @@ impl BlockChain { .enumerate() .map(|(i ,tx_hash)| { (tx_hash, Some(TransactionAddress { - block_hash: info.hash.clone(), + block_hash: info.hash, index: i })) }); @@ -1357,7 +1357,7 @@ impl BlockChain { /// Get best block hash. pub fn best_block_hash(&self) -> H256 { - self.best_block.read().hash.clone() + self.best_block.read().hash } /// Get best block number. @@ -1455,12 +1455,12 @@ impl BlockChain { total_difficulty: best_block.total_difficulty.clone(), pending_total_difficulty: best_block.total_difficulty.clone(), genesis_hash: self.genesis_hash(), - best_block_hash: best_block.hash.clone(), + best_block_hash: best_block.hash, best_block_number: best_block.number, best_block_timestamp: best_block.timestamp, first_block_hash: self.first_block(), first_block_number: From::from(self.first_block_number()), - ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash.clone()), + ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash), ancient_block_number: best_ancient_block.as_ref().map(|b| b.number), } } @@ -1473,6 +1473,7 @@ impl BlockChain { #[cfg(test)] mod tests { + use std::iter; use std::sync::Arc; use rustc_hex::FromHex; use hash::keccak; @@ -1482,13 +1483,11 @@ mod tests { use receipt::{Receipt, TransactionOutcome}; use blockchain::{BlockProvider, BlockChain, Config, ImportRoute}; use tests::helpers::*; - use blockchain::generator::{ChainGenerator, ChainIterator, BlockFinalizer}; + use blockchain::generator::{BlockGenerator, BlockBuilder, BlockOptions}; use blockchain::extras::TransactionAddress; - use views::BlockView; use transaction::{Transaction, Action}; use log_entry::{LogEntry, LocalizedLogEntry}; use ethkey::Secret; - use header::BlockNumber; fn new_db() -> Arc { Arc::new(kvdb_memorydb::create(::db::NUM_COLUMNS.unwrap_or(0))) @@ -1501,18 +1500,16 @@ mod tests { #[test] fn should_cache_best_block() { // given - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let first = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let first = genesis.add_block(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_number(), 0); // when let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first, vec![]); + bc.insert_block(&mut batch, &first.last().encoded(), vec![]); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1524,101 +1521,95 @@ mod tests { #[test] fn basic_blockchain_insert() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let first = canon_chain.generate(&mut finalizer).unwrap(); - let genesis_hash = BlockView::new(&genesis).header_view().hash(); - let first_hash = BlockView::new(&first).header_view().hash(); + let genesis = BlockBuilder::genesis(); + let first = genesis.add_block(); + + let genesis = genesis.last(); + let first = first.last(); + let genesis_hash = genesis.hash(); + let first_hash = first.hash(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.encoded(), db.clone()); - assert_eq!(bc.genesis_hash(), genesis_hash.clone()); - assert_eq!(bc.best_block_hash(), genesis_hash.clone()); - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); + assert_eq!(bc.genesis_hash(), genesis_hash); + assert_eq!(bc.best_block_hash(), genesis_hash); + assert_eq!(bc.block_hash(0), Some(genesis_hash)); assert_eq!(bc.block_hash(1), None); assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first, vec![]); + bc.insert_block(&mut batch, &first.encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); - assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); + assert_eq!(bc.block_hash(0), Some(genesis_hash)); assert_eq!(bc.best_block_number(), 1); - assert_eq!(bc.best_block_hash(), first_hash.clone()); - assert_eq!(bc.block_hash(1), Some(first_hash.clone())); - assert_eq!(bc.block_details(&first_hash).unwrap().parent, genesis_hash.clone()); - assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![first_hash.clone()]); + assert_eq!(bc.best_block_hash(), first_hash); + assert_eq!(bc.block_hash(1), Some(first_hash)); + assert_eq!(bc.block_details(&first_hash).unwrap().parent, genesis_hash); + assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![first_hash]); assert_eq!(bc.block_hash(2), None); } #[test] fn check_ancestry_iter() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let genesis_hash = BlockView::new(&genesis).header_view().hash(); + let genesis = BlockBuilder::genesis(); + let first_10 = genesis.add_blocks(10); + let generator = BlockGenerator::new(vec![first_10]); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut block_hashes = vec![genesis_hash.clone()]; + let mut block_hashes = vec![genesis.last().hash()]; let mut batch = db.transaction(); - for _ in 0..10 { - let block = canon_chain.generate(&mut finalizer).unwrap(); - block_hashes.push(BlockView::new(&block).header_view().hash()); - bc.insert_block(&mut batch, &block, vec![]); + for block in generator { + block_hashes.push(block.hash()); + bc.insert_block(&mut batch, &block.encoded(), vec![]); bc.commit(); } db.write(batch).unwrap(); block_hashes.reverse(); - assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes) + assert_eq!(bc.ancestry_iter(block_hashes[0].clone()).unwrap().collect::>(), block_hashes); + assert_eq!(block_hashes.len(), 11); } #[test] fn test_find_uncles() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let b1b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b1a = canon_chain.generate(&mut finalizer).unwrap(); - let b2b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b2a = canon_chain.generate(&mut finalizer).unwrap(); - let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b3a = canon_chain.generate(&mut finalizer).unwrap(); - let b4b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b4a = canon_chain.generate(&mut finalizer).unwrap(); - let b5b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b5a = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let b1a = genesis.add_block(); + let b2a = b1a.add_block(); + let b3a = b2a.add_block(); + let b4a = b3a.add_block(); + let b5a = b4a.add_block(); - let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let b1b = genesis.add_block_with_difficulty(9); + let b2b = b1a.add_block_with_difficulty(9); + let b3b = b2a.add_block_with_difficulty(9); + let b4b = b3a.add_block_with_difficulty(9); + let b5b = b4a.add_block_with_difficulty(9); - let mut batch =db.transaction(); - for b in &[&b1a, &b1b, &b2a, &b2b, &b3a, &b3b, &b4a, &b4b, &b5a, &b5b] { - bc.insert_block(&mut batch, b, vec![]); - bc.commit(); - } - bc.insert_block(&mut batch, &b1b, vec![]); - bc.insert_block(&mut batch, &b2a, vec![]); - bc.insert_block(&mut batch, &b2b, vec![]); - bc.insert_block(&mut batch, &b3a, vec![]); - bc.insert_block(&mut batch, &b3b, vec![]); - bc.insert_block(&mut batch, &b4a, vec![]); - bc.insert_block(&mut batch, &b4b, vec![]); - bc.insert_block(&mut batch, &b5a, vec![]); - bc.insert_block(&mut batch, &b5b, vec![]); - db.write(batch).unwrap(); + let uncle_headers = vec![b4b.last().header(), b3b.last().header(), b2b.last().header()]; + let b4a_hash = b4a.last().hash(); - assert_eq!( - [&b4b, &b3b, &b2b].iter().map(|b| BlockView::new(b).header()).collect::>(), - bc.find_uncle_headers(&BlockView::new(&b4a).header_view().hash(), 3).unwrap() + let generator = BlockGenerator::new( + vec![b1a, b1b, b2a, b2b, b3a, b3b, b4a, b4b, b5a, b5b] ); + let db = new_db(); + let bc = new_chain(&genesis.last().encoded(), db.clone()); + + let mut batch = db.transaction(); + for b in generator { + bc.insert_block(&mut batch, &b.encoded(), vec![]); + bc.commit(); + } + + db.write(batch).unwrap(); + + assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); // TODO: insert block that already includes one of them as an uncle to check it's not allowed. } @@ -1628,12 +1619,6 @@ mod tests { #[test] fn test_fork_transaction_addresses() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let mut fork_chain = canon_chain.fork(1); - let mut fork_finalizer = finalizer.fork(); - let t1 = Transaction { nonce: 0.into(), gas_price: 0.into(), @@ -1643,42 +1628,35 @@ mod tests { data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), }.sign(&secret(), None); - - let b1a = canon_chain - .with_transaction(t1.clone()) - .generate(&mut finalizer).unwrap(); - - // Empty block - let b1b = fork_chain - .generate(&mut fork_finalizer).unwrap(); - - let b2 = fork_chain - .generate(&mut fork_finalizer).unwrap(); - - let b1a_hash = BlockView::new(&b1a).header_view().hash(); - let b2_hash = BlockView::new(&b2).header_view().hash(); - let t1_hash = t1.hash(); + let genesis = BlockBuilder::genesis(); + let b1a = genesis.add_block_with_transactions(iter::once(t1)); + let b1b = genesis.add_block_with_difficulty(9); + let b2 = b1b.add_block(); + + let b1a_hash = b1a.last().hash(); + let b2_hash = b2.last().hash(); + let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a, vec![]); + let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b, vec![]); + let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b1a_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { - block_hash: b1a_hash.clone(), + block_hash: b1a_hash, index: 0, })); // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2, vec![]); + let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1687,16 +1665,8 @@ mod tests { assert_eq!(bc.transaction_address(&t1_hash), None); } - - #[test] fn test_overwriting_transaction_addresses() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let mut fork_chain = canon_chain.fork(1); - let mut fork_finalizer = finalizer.fork(); - let t1 = Transaction { nonce: 0.into(), gas_price: 0.into(), @@ -1724,103 +1694,97 @@ mod tests { data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), }.sign(&secret(), None); - let b1a = canon_chain - .with_transaction(t1.clone()) - .with_transaction(t2.clone()) - .generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let b1a = genesis.add_block_with_transactions(vec![t1.clone(), t2.clone()]); + // insert transactions in different order, + // the block has lower difficulty, so the hash is also different + let b1b = genesis.add_block_with(|| BlockOptions { + difficulty: 9.into(), + transactions: vec![t2.clone(), t1.clone()], + ..Default::default() + }); + let b2 = b1b.add_block_with_transactions(iter::once(t3.clone())); - // insert transactions in different order - let b1b = fork_chain - .with_transaction(t2.clone()) - .with_transaction(t1.clone()) - .generate(&mut fork_finalizer).unwrap(); - - let b2 = fork_chain - .with_transaction(t3.clone()) - .generate(&mut fork_finalizer).unwrap(); - - let b1a_hash = BlockView::new(&b1a).header_view().hash(); - let b1b_hash = BlockView::new(&b1b).header_view().hash(); - let b2_hash = BlockView::new(&b2).header_view().hash(); + let b1a_hash = b1a.last().hash(); + let b1b_hash = b1b.last().hash(); + let b2_hash = b2.last().hash(); let t1_hash = t1.hash(); let t2_hash = t2.hash(); let t3_hash = t3.hash(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a, vec![]); + let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b, vec![]); + let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b1a_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { - block_hash: b1a_hash.clone(), + block_hash: b1a_hash, index: 0, })); assert_eq!(bc.transaction_address(&t2_hash), Some(TransactionAddress { - block_hash: b1a_hash.clone(), + block_hash: b1a_hash, index: 1, })); // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2, vec![]); + let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.best_block_hash(), b2_hash); assert_eq!(bc.transaction_address(&t1_hash), Some(TransactionAddress { - block_hash: b1b_hash.clone(), + block_hash: b1b_hash, index: 1, })); assert_eq!(bc.transaction_address(&t2_hash), Some(TransactionAddress { - block_hash: b1b_hash.clone(), + block_hash: b1b_hash, index: 0, })); assert_eq!(bc.transaction_address(&t3_hash), Some(TransactionAddress { - block_hash: b2_hash.clone(), + block_hash: b2_hash, index: 0, })); } #[test] fn test_small_fork() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let b1 = canon_chain.generate(&mut finalizer).unwrap(); - let b2 = canon_chain.generate(&mut finalizer).unwrap(); - let b3b = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); - let b3a = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let b1 = genesis.add_block(); + let b2 = b1.add_block(); + let b3a = b2.add_block(); + let b3b = b2.add_block_with_difficulty(9); - let genesis_hash = BlockView::new(&genesis).header_view().hash(); - let b1_hash= BlockView::new(&b1).header_view().hash(); - let b2_hash= BlockView::new(&b2).header_view().hash(); - let b3a_hash= BlockView::new(&b3a).header_view().hash(); - let b3b_hash= BlockView::new(&b3b).header_view().hash(); + let genesis_hash = genesis.last().hash(); + let b1_hash = b1.last().hash(); + let b2_hash = b2.last().hash(); + let b3a_hash = b3a.last().hash(); + let b3b_hash = b3b.last().hash(); // b3a is a part of canon chain, whereas b3b is part of sidechain - let best_block_hash = b3a_hash.clone(); + let best_block_hash = b3a_hash; let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let ir1 = bc.insert_block(&mut batch, &b1, vec![]); + let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![]); bc.commit(); - let ir2 = bc.insert_block(&mut batch, &b2, vec![]); + let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); bc.commit(); - let ir3b = bc.insert_block(&mut batch, &b3b, vec![]); + let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); - let mut batch =db.transaction(); - let ir3a = bc.insert_block(&mut batch, &b3a, vec![]); + let mut batch = db.transaction(); + let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1861,79 +1825,78 @@ mod tests { assert_eq!(bc.block_hash(3).unwrap(), b3a_hash); // test trie route - let r0_1 = bc.tree_route(genesis_hash.clone(), b1_hash.clone()).unwrap(); + let r0_1 = bc.tree_route(genesis_hash, b1_hash).unwrap(); assert_eq!(r0_1.ancestor, genesis_hash); - assert_eq!(r0_1.blocks, [b1_hash.clone()]); + assert_eq!(r0_1.blocks, [b1_hash]); assert_eq!(r0_1.index, 0); - let r0_2 = bc.tree_route(genesis_hash.clone(), b2_hash.clone()).unwrap(); + let r0_2 = bc.tree_route(genesis_hash, b2_hash).unwrap(); assert_eq!(r0_2.ancestor, genesis_hash); - assert_eq!(r0_2.blocks, [b1_hash.clone(), b2_hash.clone()]); + assert_eq!(r0_2.blocks, [b1_hash, b2_hash]); assert_eq!(r0_2.index, 0); - let r1_3a = bc.tree_route(b1_hash.clone(), b3a_hash.clone()).unwrap(); + let r1_3a = bc.tree_route(b1_hash, b3a_hash).unwrap(); assert_eq!(r1_3a.ancestor, b1_hash); - assert_eq!(r1_3a.blocks, [b2_hash.clone(), b3a_hash.clone()]); + assert_eq!(r1_3a.blocks, [b2_hash, b3a_hash]); assert_eq!(r1_3a.index, 0); - let r1_3b = bc.tree_route(b1_hash.clone(), b3b_hash.clone()).unwrap(); + let r1_3b = bc.tree_route(b1_hash, b3b_hash).unwrap(); assert_eq!(r1_3b.ancestor, b1_hash); - assert_eq!(r1_3b.blocks, [b2_hash.clone(), b3b_hash.clone()]); + assert_eq!(r1_3b.blocks, [b2_hash, b3b_hash]); assert_eq!(r1_3b.index, 0); - let r3a_3b = bc.tree_route(b3a_hash.clone(), b3b_hash.clone()).unwrap(); + let r3a_3b = bc.tree_route(b3a_hash, b3b_hash).unwrap(); assert_eq!(r3a_3b.ancestor, b2_hash); - assert_eq!(r3a_3b.blocks, [b3a_hash.clone(), b3b_hash.clone()]); + assert_eq!(r3a_3b.blocks, [b3a_hash, b3b_hash]); assert_eq!(r3a_3b.index, 1); - let r1_0 = bc.tree_route(b1_hash.clone(), genesis_hash.clone()).unwrap(); + let r1_0 = bc.tree_route(b1_hash, genesis_hash).unwrap(); assert_eq!(r1_0.ancestor, genesis_hash); - assert_eq!(r1_0.blocks, [b1_hash.clone()]); + assert_eq!(r1_0.blocks, [b1_hash]); assert_eq!(r1_0.index, 1); - let r2_0 = bc.tree_route(b2_hash.clone(), genesis_hash.clone()).unwrap(); + let r2_0 = bc.tree_route(b2_hash, genesis_hash).unwrap(); assert_eq!(r2_0.ancestor, genesis_hash); - assert_eq!(r2_0.blocks, [b2_hash.clone(), b1_hash.clone()]); + assert_eq!(r2_0.blocks, [b2_hash, b1_hash]); assert_eq!(r2_0.index, 2); - let r3a_1 = bc.tree_route(b3a_hash.clone(), b1_hash.clone()).unwrap(); + let r3a_1 = bc.tree_route(b3a_hash, b1_hash).unwrap(); assert_eq!(r3a_1.ancestor, b1_hash); - assert_eq!(r3a_1.blocks, [b3a_hash.clone(), b2_hash.clone()]); + assert_eq!(r3a_1.blocks, [b3a_hash, b2_hash]); assert_eq!(r3a_1.index, 2); - let r3b_1 = bc.tree_route(b3b_hash.clone(), b1_hash.clone()).unwrap(); + let r3b_1 = bc.tree_route(b3b_hash, b1_hash).unwrap(); assert_eq!(r3b_1.ancestor, b1_hash); - assert_eq!(r3b_1.blocks, [b3b_hash.clone(), b2_hash.clone()]); + assert_eq!(r3b_1.blocks, [b3b_hash, b2_hash]); assert_eq!(r3b_1.index, 2); - let r3b_3a = bc.tree_route(b3b_hash.clone(), b3a_hash.clone()).unwrap(); + let r3b_3a = bc.tree_route(b3b_hash, b3a_hash).unwrap(); assert_eq!(r3b_3a.ancestor, b2_hash); - assert_eq!(r3b_3a.blocks, [b3b_hash.clone(), b3a_hash.clone()]); + assert_eq!(r3b_3a.blocks, [b3b_hash, b3a_hash]); assert_eq!(r3b_3a.index, 1); } #[test] fn test_reopen_blockchain_db() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let first = canon_chain.generate(&mut finalizer).unwrap(); - let genesis_hash = BlockView::new(&genesis).header_view().hash(); - let first_hash = BlockView::new(&first).header_view().hash(); + let genesis = BlockBuilder::genesis(); + let first = genesis.add_block(); + let genesis_hash = genesis.last().hash(); + let first_hash = first.last().hash(); + let db = new_db(); { - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); - let mut batch =db.transaction(); - bc.insert_block(&mut batch, &first, vec![]); + let mut batch = db.transaction(); + bc.insert_block(&mut batch, &first.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); } { - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), first_hash); } @@ -2006,11 +1969,6 @@ mod tests { #[test] fn test_logs() { - // given - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - // just insert dummy transaction so that #transactions=#receipts let t1 = Transaction { nonce: 0.into(), gas_price: 0.into(), @@ -2038,12 +1996,18 @@ mod tests { let tx_hash1 = t1.hash(); let tx_hash2 = t2.hash(); let tx_hash3 = t3.hash(); - let b1 = canon_chain.with_transaction(t1).with_transaction(t2).generate(&mut finalizer).unwrap(); - let b2 = canon_chain.with_transaction(t3).generate(&mut finalizer).unwrap(); + + let genesis = BlockBuilder::genesis(); + let b1 = genesis.add_block_with_transactions(vec![t1, t2]); + let b2 = b1.add_block_with_transactions(iter::once(t3)); + let b1_hash = b1.last().hash(); + let b1_number = b1.last().number(); + let b2_hash = b2.last().hash(); + let b2_number = b2.last().number(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); - insert_block(&db, &bc, &b1, vec![Receipt { + let bc = new_chain(&genesis.last().encoded(), db.clone()); + insert_block(&db, &bc, &b1.last().encoded(), vec![Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), log_bloom: Default::default(), @@ -2060,7 +2024,7 @@ mod tests { LogEntry { address: Default::default(), topics: vec![], data: vec![3], }, ], }]); - insert_block(&db, &bc, &b2, vec![ + insert_block(&db, &bc, &b2.last().encoded(), vec![ Receipt { outcome: TransactionOutcome::StateRoot(H256::default()), gas_used: 10_000.into(), @@ -2072,8 +2036,6 @@ mod tests { ]); // when - let block1 = BlockView::new(&b1); - let block2 = BlockView::new(&b2); let logs1 = bc.logs(vec![1, 2], |_| true, None); let logs2 = bc.logs(vec![1, 2], |_| true, Some(1)); @@ -2081,36 +2043,36 @@ mod tests { assert_eq!(logs1, vec![ LocalizedLogEntry { entry: LogEntry { address: Default::default(), topics: vec![], data: vec![1] }, - block_hash: block1.hash(), - block_number: block1.header().number(), - transaction_hash: tx_hash1.clone(), + block_hash: b1_hash, + block_number: b1_number, + transaction_hash: tx_hash1, transaction_index: 0, transaction_log_index: 0, log_index: 0, }, LocalizedLogEntry { entry: LogEntry { address: Default::default(), topics: vec![], data: vec![2] }, - block_hash: block1.hash(), - block_number: block1.header().number(), - transaction_hash: tx_hash1.clone(), + block_hash: b1_hash, + block_number: b1_number, + transaction_hash: tx_hash1, transaction_index: 0, transaction_log_index: 1, log_index: 1, }, LocalizedLogEntry { entry: LogEntry { address: Default::default(), topics: vec![], data: vec![3] }, - block_hash: block1.hash(), - block_number: block1.header().number(), - transaction_hash: tx_hash2.clone(), + block_hash: b1_hash, + block_number: b1_number, + transaction_hash: tx_hash2, transaction_index: 1, transaction_log_index: 0, log_index: 2, }, LocalizedLogEntry { entry: LogEntry { address: Default::default(), topics: vec![], data: vec![4] }, - block_hash: block2.hash(), - block_number: block2.header().number(), - transaction_hash: tx_hash3.clone(), + block_hash: b2_hash, + block_number: b2_number, + transaction_hash: tx_hash3, transaction_index: 0, transaction_log_index: 0, log_index: 0, @@ -2119,9 +2081,9 @@ mod tests { assert_eq!(logs2, vec![ LocalizedLogEntry { entry: LogEntry { address: Default::default(), topics: vec![], data: vec![4] }, - block_hash: block2.hash(), - block_number: block2.header().number(), - transaction_hash: tx_hash3.clone(), + block_hash: b2_hash, + block_number: b2_number, + transaction_hash: tx_hash3, transaction_index: 0, transaction_log_index: 0, log_index: 0, @@ -2131,64 +2093,64 @@ mod tests { #[test] fn test_bloom_filter_simple() { - // TODO: From here let bloom_b1: Bloom = "00000020000000000000000000000000000000000000000002000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000400000000000000000000002000".into(); let bloom_b2: Bloom = "00000000000000000000000000000000000000000000020000001000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(); let bloom_ba: Bloom = "00000000000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000008000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(); - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let mut fork = canon_chain.fork(1); - let mut fork_finalizer = finalizer.fork(); - let b1 = fork.with_bloom(bloom_b1.clone()).generate(&mut fork_finalizer).unwrap(); - let b2 = fork.with_bloom(bloom_b2.clone()).generate(&mut fork_finalizer).unwrap(); - let b3 = fork.with_bloom(bloom_ba.clone()).generate(&mut fork_finalizer).unwrap(); - let b1a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); - let b2a = canon_chain.with_bloom(bloom_ba.clone()).generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let b1 = genesis.add_block_with(|| BlockOptions { + bloom: bloom_b1.clone(), + difficulty: 9.into(), + ..Default::default() + }); + let b2 = b1.add_block_with_bloom(bloom_b2); + let b3 = b2.add_block_with_bloom(bloom_ba); + + let b1a = genesis.add_block_with_bloom(bloom_ba); + let b2a = b1a.add_block_with_bloom(bloom_ba); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); - assert_eq!(blocks_b1, Vec::::new()); - assert_eq!(blocks_b2, Vec::::new()); + assert!(blocks_b1.is_empty()); + assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b1, vec![]); + insert_block(&db, &bc, &b1.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![1]); - assert_eq!(blocks_b2, Vec::::new()); + assert!(blocks_b2.is_empty()); - insert_block(&db, &bc, &b2, vec![]); + insert_block(&db, &bc, &b2.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); // hasn't been forked yet - insert_block(&db, &bc, &b1a, vec![]); + insert_block(&db, &bc, &b1a.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); assert_eq!(blocks_b1, vec![1]); assert_eq!(blocks_b2, vec![2]); - assert_eq!(blocks_ba, Vec::::new()); + assert!(blocks_ba.is_empty()); // fork has happend - insert_block(&db, &bc, &b2a, vec![]); + insert_block(&db, &bc, &b2a.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); - assert_eq!(blocks_b1, Vec::::new()); - assert_eq!(blocks_b2, Vec::::new()); + assert!(blocks_b1.is_empty()); + assert!(blocks_b2.is_empty()); assert_eq!(blocks_ba, vec![1, 2]); // fork back - insert_block(&db, &bc, &b3, vec![]); + insert_block(&db, &bc, &b3.last().encoded(), vec![]); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); let blocks_ba = bc.blocks_with_bloom(&bloom_ba, 0, 5); @@ -2199,61 +2161,55 @@ mod tests { #[test] fn test_best_block_update() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let next_5 = genesis.add_blocks(5); + let uncle = genesis.add_block_with_difficulty(9); + let generator = BlockGenerator::new(iter::once(next_5)); let db = new_db(); { - let bc = new_chain(&genesis, db.clone()); - let uncle = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); // create a longer fork - for _ in 0..5 { - let canon_block = canon_chain.generate(&mut finalizer).unwrap(); - bc.insert_block(&mut batch, &canon_block, vec![]); + for block in generator { + bc.insert_block(&mut batch, &block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle, vec![]); + bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis, db); + let bc = new_chain(&genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); } #[test] fn test_rewind() { - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); - let first = canon_chain.generate(&mut finalizer).unwrap(); - let second = canon_chain.generate(&mut finalizer).unwrap(); - let genesis_hash = BlockView::new(&genesis).header_view().hash(); - let first_hash = BlockView::new(&first).header_view().hash(); - let second_hash = BlockView::new(&second).header_view().hash(); + let genesis = BlockBuilder::genesis(); + let first = genesis.add_block(); + let second = first.add_block(); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut batch =db.transaction(); - bc.insert_block(&mut batch, &first, vec![]); + let mut batch = db.transaction(); + bc.insert_block(&mut batch, &first.last().encoded(), vec![]); bc.commit(); - bc.insert_block(&mut batch, &second, vec![]); + bc.insert_block(&mut batch, &second.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); - assert_eq!(bc.rewind(), Some(first_hash.clone())); - assert!(!bc.is_known(&second_hash)); + assert_eq!(bc.rewind(), Some(first.last().hash())); + assert!(!bc.is_known(&second.last().hash())); assert_eq!(bc.best_block_number(), 1); - assert_eq!(bc.best_block_hash(), first_hash.clone()); + assert_eq!(bc.best_block_hash(), first.last().hash()); - assert_eq!(bc.rewind(), Some(genesis_hash.clone())); + assert_eq!(bc.rewind(), Some(genesis.last().hash())); assert_eq!(bc.rewind(), None); } @@ -2261,25 +2217,23 @@ mod tests { fn epoch_transitions_iter() { use ::engines::EpochTransition; - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let next_5 = genesis.add_blocks(5); + let uncle = genesis.add_block_with_difficulty(9); + let generator = BlockGenerator::new(iter::once(next_5)); let db = new_db(); { - let bc = new_chain(&genesis, db.clone()); - let uncle = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); + let bc = new_chain(&genesis.last().encoded(), db.clone()); 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().hash(); + for (i, block) in generator.into_iter().enumerate() { - bc.insert_block(&mut batch, &canon_block, vec![]); - bc.insert_epoch_transition(&mut batch, i, EpochTransition { - block_hash: hash, - block_number: i + 1, + bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { + block_hash: block.hash(), + block_number: i as u64 + 1, proof: vec![], }); bc.commit(); @@ -2287,10 +2241,9 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - let hash = BlockView::new(&uncle).header_view().hash(); - bc.insert_block(&mut batch, &uncle, vec![]); + bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { - block_hash: hash, + block_hash: uncle.last().hash(), block_number: 1, proof: vec![], }); @@ -2303,7 +2256,7 @@ mod tests { } // re-loading the blockchain should load the correct best block. - let bc = new_chain(&genesis, db); + let bc = new_chain(&genesis.last().encoded(), db); assert_eq!(bc.best_block_number(), 5); assert_eq!(bc.epoch_transitions().map(|(i, _)| i).collect::>(), vec![0, 1, 2, 3, 4]); @@ -2313,13 +2266,18 @@ mod tests { fn epoch_transition_for() { use ::engines::EpochTransition; - let mut canon_chain = ChainGenerator::default(); - let mut finalizer = BlockFinalizer::default(); - let genesis = canon_chain.generate(&mut finalizer).unwrap(); + let genesis = BlockBuilder::genesis(); + let fork_7 = genesis.add_blocks_with(7, || BlockOptions { + difficulty: 9.into(), + ..Default::default() + }); + let next_10 = genesis.add_blocks(10); + let fork_generator = BlockGenerator::new(iter::once(fork_7)); + let next_generator = BlockGenerator::new(iter::once(next_10)); let db = new_db(); - let bc = new_chain(&genesis, db.clone()); + let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); bc.insert_epoch_transition(&mut batch, 0, EpochTransition { @@ -2332,14 +2290,10 @@ mod tests { // set up a chain where we have a canonical chain of 10 blocks // and a non-canonical fork of 8 from genesis. let fork_hash = { - let mut fork_chain = canon_chain.fork(1); - let mut fork_finalizer = finalizer.fork(); - - for _ in 0..7 { + for block in fork_generator { let mut batch = db.transaction(); - let fork_block = fork_chain.generate(&mut fork_finalizer).unwrap(); - bc.insert_block(&mut batch, &fork_block, vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); } @@ -2348,11 +2302,9 @@ mod tests { bc.chain_info().best_block_hash }; - for _ in 0..10 { + for block in next_generator { let mut batch = db.transaction(); - let canon_block = canon_chain.generate(&mut finalizer).unwrap(); - - bc.insert_block(&mut batch, &canon_block, vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); diff --git a/ethcore/src/blockchain/generator.rs b/ethcore/src/blockchain/generator.rs new file mode 100644 index 000000000..5c9068721 --- /dev/null +++ b/ethcore/src/blockchain/generator.rs @@ -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 . + +//! 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, + pub uncles: Vec
+} + +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, +} + +impl Default for BlockOptions { + fn default() -> Self { + BlockOptions { + difficulty: 10.into(), + bloom: Bloom::default(), + transactions: Vec::new(), + } + } +} + +#[derive(Clone)] +pub struct BlockBuilder { + blocks: VecDeque, +} + +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(&self, get_metadata: T) -> Self where T: Fn() -> BlockOptions { + self.add_blocks_with(1, get_metadata) + } + + #[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() + }) + } + + #[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() + }) + } + + #[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(&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, +} + +impl BlockGenerator { + 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, 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); + } +} diff --git a/ethcore/src/blockchain/generator/block.rs b/ethcore/src/blockchain/generator/block.rs deleted file mode 100644 index 2ac244e83..000000000 --- a/ethcore/src/blockchain/generator/block.rs +++ /dev/null @@ -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 . - -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, - pub uncles: Vec
-} - -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() - } -} diff --git a/ethcore/src/blockchain/generator/bloom.rs b/ethcore/src/blockchain/generator/bloom.rs deleted file mode 100644 index f6748f3aa..000000000 --- a/ethcore/src/blockchain/generator/bloom.rs +++ /dev/null @@ -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 . - -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, ::Item: WithBloom { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|item| item.with_bloom(self.bloom.clone())) - } -} diff --git a/ethcore/src/blockchain/generator/complete.rs b/ethcore/src/blockchain/generator/complete.rs deleted file mode 100644 index 160f0f484..000000000 --- a/ethcore/src/blockchain/generator/complete.rs +++ /dev/null @@ -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 . - -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, ::Item: CompleteBlock { - type Item = Bytes; - - #[inline] - fn next(&mut self) -> Option { - 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 - }) - } -} diff --git a/ethcore/src/blockchain/generator/fork.rs b/ethcore/src/blockchain/generator/fork.rs deleted file mode 100644 index 4f09f3c04..000000000 --- a/ethcore/src/blockchain/generator/fork.rs +++ /dev/null @@ -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 . - -pub trait Forkable { - fn fork(self, fork_number: usize) -> Self where Self: Sized; -} - -pub struct Fork { - pub iter: I, - pub fork_number: usize, -} - -impl Clone for Fork where I: Iterator + Clone { - fn clone(&self) -> Self { - Fork { - iter: self.iter.clone(), - fork_number: self.fork_number - } - } -} - -impl Iterator for Fork where I: Iterator, ::Item: Forkable { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|item| item.fork(self.fork_number)) - } -} diff --git a/ethcore/src/blockchain/generator/generator.rs b/ethcore/src/blockchain/generator/generator.rs deleted file mode 100644 index e06e08902..000000000 --- a/ethcore/src/blockchain/generator/generator.rs +++ /dev/null @@ -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 . - -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 where Self: Clone; - /// Should be called to make every consecutive block have given bloom. - fn with_bloom(&mut self, bloom: LogBloom) -> Bloom; - /// Should be called to make every consecutive block have given transaction. - fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction; - /// 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 where Self::Item: CompleteBlock; -} - -impl ChainIterator for I where I: Iterator + Sized { - fn fork(&self, fork_number: usize) -> Fork where I: Clone { - Fork { - iter: self.clone(), - fork_number: fork_number - } - } - - fn with_bloom(&mut self, bloom: LogBloom) -> Bloom { - Bloom { - iter: self, - bloom: bloom - } - } - - fn with_transaction(&mut self, transaction: SignedTransaction) -> Transaction { - 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 where ::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 { - 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); - } -} - diff --git a/ethcore/src/blockchain/generator/mod.rs b/ethcore/src/blockchain/generator/mod.rs deleted file mode 100644 index c32c4a3d7..000000000 --- a/ethcore/src/blockchain/generator/mod.rs +++ /dev/null @@ -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 . - -//! 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}; diff --git a/ethcore/src/blockchain/generator/transaction.rs b/ethcore/src/blockchain/generator/transaction.rs deleted file mode 100644 index c2c89ace7..000000000 --- a/ethcore/src/blockchain/generator/transaction.rs +++ /dev/null @@ -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 . - -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, ::Item: WithTransaction { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|item| item.with_transaction(self.transaction.clone())) - } -} diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index f51586a03..e41b61e6e 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -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,