rollback function for storage

This commit is contained in:
NikVolf 2016-11-29 17:24:04 +03:00
parent 36f83639ec
commit eb808f7449
1 changed files with 60 additions and 0 deletions

View File

@ -383,6 +383,34 @@ impl Storage {
Ok(Some(reorganization))
}
/// Decanonizes main chain until best block is the one with `hash`
pub fn rollback(&self, hash: &H256) -> Result<Vec<H256>, Error> {
if self.block_number(hash).is_none() {
return Err(Error::not_main(hash));
}
// lock will be held until the end of the routine
let mut best_block = self.best_block.write();
let mut context = UpdateContext::new(&self.database);
let mut result = Vec::new();
let mut best_number = try!(self.best_number().ok_or(Error::Consistency(ConsistencyError::NoBestBlock)));
loop {
let next = try!(self.block_hash(best_number).ok_or(Error::unknown_number(best_number)));
if &next == hash {
context.db_transaction.put(Some(COL_META), KEY_BEST_BLOCK_HASH, &**hash);
context.db_transaction.write_u32(Some(COL_META), KEY_BEST_BLOCK_NUMBER, best_number);
try!(context.apply(&self.database));
*best_block = Some(BestBlock { hash: next, number: best_number });
return Ok(result);
}
try!(self.decanonize_block(&mut context, &next));
best_number -= 1;
result.push(next);
}
}
}
impl BlockProvider for Storage {
@ -1334,6 +1362,38 @@ mod tests {
});
}
#[test]
fn rollback() {
let path = RandomTempPath::create_dir();
let store = Storage::new(path.as_path()).unwrap();
let genesis = test_data::genesis();
store.insert_block(&genesis).unwrap();
let (main_hash1, main_block1) = test_data::block_hash_builder()
.block()
.header().parent(genesis.hash())
.nonce(1)
.build()
.build()
.build();
store.insert_block(&main_block1).expect("main block 1 should insert with no problems");
let (main_hash2, main_block2) = test_data::block_hash_builder()
.block()
.header().parent(main_hash1.clone())
.nonce(2)
.build()
.build()
.build();
store.insert_block(&main_block2).expect("main block 2 should insert with no problems");
assert_eq!(store.best_block().unwrap().hash, main_hash2);
store.rollback(&main_hash1).unwrap();
assert_eq!(store.best_block().unwrap().hash, main_hash1);
}
#[test]
fn fork_route() {
let path = RandomTempPath::create_dir();