rollback function for storage
This commit is contained in:
parent
36f83639ec
commit
eb808f7449
|
@ -383,6 +383,34 @@ impl Storage {
|
||||||
|
|
||||||
Ok(Some(reorganization))
|
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 {
|
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]
|
#[test]
|
||||||
fn fork_route() {
|
fn fork_route() {
|
||||||
let path = RandomTempPath::create_dir();
|
let path = RandomTempPath::create_dir();
|
||||||
|
|
Loading…
Reference in New Issue