block insert in one batch to extras

This commit is contained in:
debris 2015-12-21 14:23:10 +01:00
parent 491cc29a09
commit f9457cc584

View File

@ -209,15 +209,23 @@ impl BlockChain {
/// ```json /// ```json
/// { blocks: [B4, B3, A3, A4], ancestor: A2, index: 2 } /// { 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 from_branch = vec![];
let mut to_branch = vec![]; let mut to_branch = vec![];
let mut from_details = self.block_details(from).expect("from hash is invalid!"); let mut from_details = from.0;
let mut to_details = self.block_details(to).expect("to hash is invalid!"); let mut to_details = to.0;
let mut current_from = from.1;
let mut current_from = from.clone(); let mut current_to = to.1;
let mut current_to = to.clone();
// reset from && to to the same level // reset from && to to the same level
while from_details.number > to_details.number { while from_details.number > to_details.number {
@ -256,6 +264,7 @@ impl BlockChain {
} }
} }
/// Inserts the block into backing cache database. /// Inserts the block into backing cache database.
/// Expects the block to be valid and already verified. /// Expects the block to be valid and already verified.
/// If the block is already known, does nothing. /// If the block is already known, does nothing.
@ -272,6 +281,7 @@ impl BlockChain {
let hash = block.sha3(); let hash = block.sha3();
let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash."); let mut parent_details = self.block_details(&header.parent_hash()).expect("Invalid parent hash.");
let total_difficulty = parent_details.total_difficulty + header.difficulty(); 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(); let parent_hash = header.parent_hash();
// create current block details // create current block details
@ -285,67 +295,62 @@ impl BlockChain {
// store block in db // store block in db
self.blocks_db.put(&hash, &bytes).unwrap(); self.blocks_db.put(&hash, &bytes).unwrap();
// update extra details let batch = WriteBatch::new();
// prepare update for extra details
{ {
// insert new block details // insert new block details
let batch = WriteBatch::new();
batch.put_extras(&hash, &details); batch.put_extras(&hash, &details);
// update parent details // update parent details
parent_details.children.push(hash.clone()); parent_details.children.push(hash.clone());
batch.put_extras(&parent_hash, &parent_details); 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 its new best block we need to make sure that all ancestors
// if yes, it means that we need to move it and its ancestors // are moved to "canon chain"
// to "canon chain" if is_new_best {
if total_difficulty > self.best_block_total_difficulty() {
// find the route between old best block and the new one // 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 // its our parent
1 => { 1 => batch.put_extras(&header.number(), &hash),
let extras = WriteBatch::new();
extras.put_extras(&header.number(), &hash);
extras
},
// it is a fork // it is a fork
i if i > 1 => { i if i > 1 => {
let ancestor_number = self.block_number(&route.ancestor).unwrap(); let ancestor_number = self.block_number(&route.ancestor).unwrap();
let start_number = ancestor_number + U256::from(1u8); let start_number = ancestor_number + U256::from(1u8);
route.blocks.iter() for (index, hash) in route.blocks.iter().skip(route.index).enumerate() {
.skip(route.index) batch.put_extras(&(start_number + U256::from(index as u64)), hash);
.enumerate() }
.fold(WriteBatch::new(), | acc, (index, hash) | {
acc.put_extras(&(start_number + U256::from(index as u64)), hash);
acc
})
}, },
// route.len() could be 0 only if inserted block is best block, // route.len() could be 0 only if inserted block is best block,
// and this is not possible at this stage // and this is not possible at this stage
_ => { unreachable!(); } _ => { unreachable!(); }
}; };
// update extras database // this is new extras db
extras_batch.put(b"best", &hash).unwrap(); batch.put(b"best", &hash).unwrap();
self.extras_db.write(extras_batch).unwrap(); }
// apply update
{
// update local caches // update local caches
let mut best_block = self.best_block.borrow_mut(); let mut best_block = self.best_block.borrow_mut();
if is_new_best {
best_block.hash = hash; best_block.hash = hash;
best_block.number = header.number(); best_block.number = header.number();
best_block.total_difficulty = total_difficulty; 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();
}
} }
/// Returns true if the given block is known /// Returns true if the given block is known