Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Commit

Permalink
Added client function to delete a recent block (paritytech#8533)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
2 people authored and nazar-pc committed Aug 8, 2021
1 parent 70504fa commit ebd7786
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 48 deletions.
6 changes: 6 additions & 0 deletions client/api/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,12 @@ pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
revert_finalized: bool,
) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;

/// Discard non-best, unfinalized leaf block.
fn remove_leaf_block(
&self,
hash: &Block::Hash,
) -> sp_blockchain::Result<()>;

/// Insert auxiliary data into key-value store.
fn insert_aux<
'a,
Expand Down
7 changes: 7 additions & 0 deletions client/api/src/in_mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,13 @@ impl<Block: BlockT> backend::Backend<Block> for Backend<Block> where Block::Hash
Ok((Zero::zero(), HashSet::new()))
}

fn remove_leaf_block(
&self,
_hash: &Block::Hash,
) -> sp_blockchain::Result<()> {
Ok(())
}

fn get_import_lock(&self) -> &RwLock<()> {
&self.import_lock
}
Expand Down
4 changes: 2 additions & 2 deletions client/api/src/leaves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ impl<H, N> LeafSet<H, N> where
self.pending_removed.clear();
}

#[cfg(test)]
fn contains(&self, number: N, hash: H) -> bool {
/// Check if given block is a leaf.
pub fn contains(&self, number: N, hash: H) -> bool {
self.storage.get(&Reverse(number)).map_or(false, |hashes| hashes.contains(&hash))
}

Expand Down
86 changes: 86 additions & 0 deletions client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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));
}
}
7 changes: 7 additions & 0 deletions client/light/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ impl<S, Block> ClientBackend<Block> for Backend<S, HashFor<Block>>
Err(ClientError::NotAvailableOnLightClient)
}

fn remove_leaf_block(
&self,
_hash: &Block::Hash,
) -> ClientResult<()> {
Err(ClientError::NotAvailableOnLightClient)
}

fn get_import_lock(&self) -> &RwLock<()> {
&self.import_lock
}
Expand Down
17 changes: 17 additions & 0 deletions client/state-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,17 @@ impl<BlockHash: Hash + MallocSizeOf, Key: Hash + MallocSizeOf> StateDbSync<Block
}
}

fn remove(&mut self, hash: &BlockHash) -> Option<CommitSet<Key>> {
match self.mode {
PruningMode::ArchiveAll => {
Some(CommitSet::default())
},
PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => {
self.non_canonical.remove(hash)
},
}
}

fn pin(&mut self, hash: &BlockHash) -> Result<(), PinError> {
match self.mode {
PruningMode::ArchiveAll => Ok(()),
Expand Down Expand Up @@ -509,6 +520,12 @@ impl<BlockHash: Hash + MallocSizeOf, Key: Hash + MallocSizeOf> StateDb<BlockHash
self.db.write().revert_one()
}

/// Remove specified non-canonical block.
/// Returns a database commit or `None` if not possible.
pub fn remove(&self, hash: &BlockHash) -> Option<CommitSet<Key>> {
self.db.write().remove(hash)
}

/// Returns last finalized block number.
pub fn best_canonical(&self) -> Option<u64> {
return self.db.read().best_canonical()
Expand Down
Loading

0 comments on commit ebd7786

Please sign in to comment.