From f9457cc58405be6df41e4169b88e560ba90356da Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 21 Dec 2015 14:23:10 +0100 Subject: [PATCH] block insert in one batch to extras --- src/blockchain.rs | 87 +++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/src/blockchain.rs b/src/blockchain.rs index 308d5a2a5..287224c23 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -209,15 +209,23 @@ impl BlockChain { /// ```json /// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 } /// ``` - pub fn tree_route(&self, from: &H256, to: &H256) -> TreeRoute { + pub fn tree_route(&self, from: H256, to: H256) -> TreeRoute { + let from_details = self.block_details(&from).expect("from hash is invalid!"); + let to_details = self.block_details(&to).expect("to hash is invalid!"); + + self._tree_route((from_details, from), (to_details, to)) + } + + /// Same as `tree_route` function, but returns a root between blocks that may not + /// be in database yet + fn _tree_route(&self, from: (BlockDetails, H256), to: (BlockDetails, H256)) -> TreeRoute { let mut from_branch = vec![]; let mut to_branch = vec![]; - let mut from_details = self.block_details(from).expect("from hash is invalid!"); - let mut to_details = self.block_details(to).expect("to hash is invalid!"); - - let mut current_from = from.clone(); - let mut current_to = to.clone(); + let mut from_details = from.0; + let mut to_details = to.0; + let mut current_from = from.1; + let mut current_to = to.1; // reset from && to to the same level while from_details.number > to_details.number { @@ -256,6 +264,7 @@ impl BlockChain { } } + /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. @@ -272,6 +281,7 @@ impl BlockChain { let hash = block.sha3(); let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash."); let total_difficulty = parent_details.total_difficulty + header.difficulty(); + let is_new_best = total_difficulty > self.best_block_total_difficulty(); let parent_hash = header.parent_hash(); // create current block details @@ -285,66 +295,61 @@ impl BlockChain { // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); - // update extra details + let batch = WriteBatch::new(); + // prepare update for extra details { // insert new block details - let batch = WriteBatch::new(); batch.put_extras(&hash, &details); // update parent details parent_details.children.push(hash.clone()); batch.put_extras(&parent_hash, &parent_details); - self.extras_db.write(batch).unwrap(); - - // also in cache if it's there... - let mut write = self.block_details.borrow_mut(); - match write.get_mut(&parent_hash) { - Some(parent_details) => parent_details.children.push(hash.clone()), - None => () - } } - // check if we have new best block. - // if yes, it means that we need to move it and its ancestors - // to "canon chain" - if total_difficulty > self.best_block_total_difficulty() { - + // if its new best block we need to make sure that all ancestors + // are moved to "canon chain" + if is_new_best { // find the route between old best block and the new one - let route = self.tree_route(&self.best_block_hash(), &hash); + let best_hash = self.best_block_hash(); + let best_details = self.block_details(&best_hash).expect("best block hash is invalid!"); + let route = self._tree_route((best_details, best_hash), (details, hash.clone())); - let extras_batch = match route.blocks.len() { + match route.blocks.len() { // its our parent - 1 => { - let extras = WriteBatch::new(); - extras.put_extras(&header.number(), &hash); - extras - }, + 1 => batch.put_extras(&header.number(), &hash), // it is a fork i if i > 1 => { let ancestor_number = self.block_number(&route.ancestor).unwrap(); let start_number = ancestor_number + U256::from(1u8); - route.blocks.iter() - .skip(route.index) - .enumerate() - .fold(WriteBatch::new(), | acc, (index, hash) | { - acc.put_extras(&(start_number + U256::from(index as u64)), hash); - acc - }) + for (index, hash) in route.blocks.iter().skip(route.index).enumerate() { + batch.put_extras(&(start_number + U256::from(index as u64)), hash); + } }, // route.len() could be 0 only if inserted block is best block, // and this is not possible at this stage _ => { unreachable!(); } }; - // update extras database - extras_batch.put(b"best", &hash).unwrap(); - self.extras_db.write(extras_batch).unwrap(); + // this is new extras db + batch.put(b"best", &hash).unwrap(); + } + // apply update + { // update local caches let mut best_block = self.best_block.borrow_mut(); - best_block.hash = hash; - best_block.number = header.number(); - best_block.total_difficulty = total_difficulty; + if is_new_best { + best_block.hash = hash; + best_block.number = header.number(); + best_block.total_difficulty = total_difficulty; + } + + // remove outdated cached parent details + let mut write = self.block_details.borrow_mut(); + write.remove(&parent_hash); + + // update extras database + self.extras_db.write(batch).unwrap(); } }