Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Added client function to delete a recent block #8533

Merged
3 commits merged into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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