Added client function to delete a recent block (#8533)

* Implemented recent block removal

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Arkadiy Paronyan
2021-05-05 19:16:34 +03:00
committed by GitHub
parent 7c3a3f79ba
commit d11e60510e
7 changed files with 295 additions and 49 deletions
+86
View File
@@ -623,6 +623,7 @@ impl<Block: BlockT> HeaderMetadata<Block> for BlockchainDb<Block> {
}
fn remove_header_metadata(&self, hash: Block::Hash) {
self.header_cache.lock().remove(&hash);
self.header_metadata_cache.remove_header_metadata(hash);
}
}
@@ -1972,6 +1973,59 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
Ok((reverted, reverted_finalized))
}
fn remove_leaf_block(
&self,
hash: &Block::Hash,
) -> ClientResult<()> {
let best_hash = self.blockchain.info().best_hash;
if best_hash == *hash {
return Err(
sp_blockchain::Error::Backend(
format!("Can't remove best block {:?}", hash)
)
)
}
let hdr = self.blockchain.header_metadata(hash.clone())?;
if !self.have_state_at(&hash, hdr.number) {
return Err(
sp_blockchain::Error::UnknownBlock(
format!("State already discarded for {:?}", hash)
)
)
}
let mut leaves = self.blockchain.leaves.write();
if !leaves.contains(hdr.number, *hash) {
return Err(
sp_blockchain::Error::Backend(
format!("Can't remove non-leaf block {:?}", hash)
)
)
}
let mut transaction = Transaction::new();
if let Some(commit) = self.storage.state_db.remove(hash) {
apply_state_commit(&mut transaction, commit);
}
transaction.remove(columns::KEY_LOOKUP, hash.as_ref());
let changes_trie_cache_ops = self.changes_tries_storage.revert(
&mut transaction,
&cache::ComplexBlockId::new(
*hash,
hdr.number,
),
)?;
self.changes_tries_storage.post_commit(Some(changes_trie_cache_ops));
leaves.revert(hash.clone(), hdr.number);
leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX);
self.storage.db.commit(transaction)?;
self.blockchain().remove_header_metadata(*hash);
Ok(())
}
fn blockchain(&self) -> &BlockchainDb<Block> {
&self.blockchain
}
@@ -3008,4 +3062,36 @@ pub(crate) mod tests {
}
}
}
#[test]
fn remove_leaf_block_works() {
let backend = Backend::<Block>::new_test_with_tx_storage(
2,
10,
TransactionStorageMode::StorageChain
);
let mut blocks = Vec::new();
let mut prev_hash = Default::default();
for i in 0 .. 2 {
let hash = insert_block(&backend, i, prev_hash, None, Default::default(), vec![i.into()], None);
blocks.push(hash);
prev_hash = hash;
}
// insert a fork at block 2, which becomes best block
let best_hash = insert_block(
&backend,
1,
blocks[0],
None,
sp_core::H256::random(),
vec![42.into()],
None
);
assert!(backend.remove_leaf_block(&best_hash).is_err());
assert!(backend.have_state_at(&prev_hash, 1));
backend.remove_leaf_block(&prev_hash).unwrap();
assert_eq!(None, backend.blockchain().header(BlockId::hash(prev_hash.clone())).unwrap());
assert!(!backend.have_state_at(&prev_hash, 1));
}
}