mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Synchronize state cache on finalization (#3246)
* Reorg test * Fixed informant misreporting reorgs * Update cache when reorg is caused by applying finality * Test for finality reorg * Simplified test * Typo Co-Authored-By: André Silva <andre.beat@gmail.com>
This commit is contained in:
committed by
André Silva
parent
1295260f2b
commit
1d5cd20c44
@@ -1108,21 +1108,24 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(set_head) = operation.set_head {
|
||||
let cache_update = if let Some(set_head) = operation.set_head {
|
||||
if let Some(header) = ::client::blockchain::HeaderBackend::header(&self.blockchain, set_head)? {
|
||||
let number = header.number();
|
||||
let hash = header.hash();
|
||||
|
||||
self.set_head_with_transaction(
|
||||
let (enacted, retracted) = self.set_head_with_transaction(
|
||||
&mut transaction,
|
||||
hash.clone(),
|
||||
(number.clone(), hash.clone())
|
||||
)?;
|
||||
meta_updates.push((hash, *number, true, false));
|
||||
Some((enacted, retracted))
|
||||
} else {
|
||||
return Err(client::error::Error::UnknownBlock(format!("Cannot set head {:?}", set_head)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let write_result = self.storage.db.write(transaction).map_err(db_err);
|
||||
|
||||
@@ -1152,6 +1155,10 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
|
||||
);
|
||||
}
|
||||
|
||||
if let Some((enacted, retracted)) = cache_update {
|
||||
self.shared_cache.lock().sync(&enacted, &retracted);
|
||||
}
|
||||
|
||||
for (hash, number, is_best, is_finalized) in meta_updates {
|
||||
self.blockchain.update_meta(hash, number, is_best, is_finalized);
|
||||
}
|
||||
|
||||
@@ -151,6 +151,65 @@ impl<B: BlockT, H: Hasher> Cache<B, H> {
|
||||
+ self.lru_child_storage.used_size()
|
||||
// ignore small hashes storage and self.lru_hashes.used_size()
|
||||
}
|
||||
|
||||
/// Synchronize the shared cache with the best block state.
|
||||
/// This function updates the shared cache by removing entries
|
||||
/// that are invalidated by chain reorganization. It should be
|
||||
/// be called when chain reorg happens without importing a new block.
|
||||
pub fn sync(&mut self, enacted: &[B::Hash], retracted: &[B::Hash]) {
|
||||
trace!("Syncing shared cache, enacted = {:?}, retracted = {:?}", enacted, retracted);
|
||||
|
||||
// Purge changes from re-enacted and retracted blocks.
|
||||
// Filter out commiting block if any.
|
||||
let mut clear = false;
|
||||
for block in enacted {
|
||||
clear = clear || {
|
||||
if let Some(ref mut m) = self.modifications.iter_mut().find(|m| &m.hash == block) {
|
||||
trace!("Reverting enacted block {:?}", block);
|
||||
m.is_canon = true;
|
||||
for a in &m.storage {
|
||||
trace!("Reverting enacted key {:?}", a);
|
||||
self.lru_storage.remove(a);
|
||||
}
|
||||
for a in &m.child_storage {
|
||||
trace!("Reverting enacted child key {:?}", a);
|
||||
self.lru_child_storage.remove(a);
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for block in retracted {
|
||||
clear = clear || {
|
||||
if let Some(ref mut m) = self.modifications.iter_mut().find(|m| &m.hash == block) {
|
||||
trace!("Retracting block {:?}", block);
|
||||
m.is_canon = false;
|
||||
for a in &m.storage {
|
||||
trace!("Retracted key {:?}", a);
|
||||
self.lru_storage.remove(a);
|
||||
}
|
||||
for a in &m.child_storage {
|
||||
trace!("Retracted child key {:?}", a);
|
||||
self.lru_child_storage.remove(a);
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
}
|
||||
if clear {
|
||||
// We don't know anything about the block; clear everything
|
||||
trace!("Wiping cache");
|
||||
self.lru_storage.clear();
|
||||
self.lru_child_storage.clear();
|
||||
self.lru_hashes.clear();
|
||||
self.modifications.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SharedCache<B, H> = Arc<Mutex<Cache<B, H>>>;
|
||||
@@ -247,58 +306,12 @@ impl<H: Hasher, B: BlockT> CacheChanges<H, B> {
|
||||
let is_best = is_best();
|
||||
trace!("Syncing cache, id = (#{:?}, {:?}), parent={:?}, best={}", commit_number, commit_hash, self.parent_hash, is_best);
|
||||
let cache = &mut *cache;
|
||||
|
||||
// Purge changes from re-enacted and retracted blocks.
|
||||
// Filter out commiting block if any.
|
||||
let mut clear = false;
|
||||
for block in enacted.iter().filter(|h| commit_hash.as_ref().map_or(true, |p| *h != p)) {
|
||||
clear = clear || {
|
||||
if let Some(ref mut m) = cache.modifications.iter_mut().find(|m| &m.hash == block) {
|
||||
trace!("Reverting enacted block {:?}", block);
|
||||
m.is_canon = true;
|
||||
for a in &m.storage {
|
||||
trace!("Reverting enacted key {:?}", a);
|
||||
cache.lru_storage.remove(a);
|
||||
}
|
||||
for a in &m.child_storage {
|
||||
trace!("Reverting enacted child key {:?}", a);
|
||||
cache.lru_child_storage.remove(a);
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for block in retracted {
|
||||
clear = clear || {
|
||||
if let Some(ref mut m) = cache.modifications.iter_mut().find(|m| &m.hash == block) {
|
||||
trace!("Retracting block {:?}", block);
|
||||
m.is_canon = false;
|
||||
for a in &m.storage {
|
||||
trace!("Retracted key {:?}", a);
|
||||
cache.lru_storage.remove(a);
|
||||
}
|
||||
for a in &m.child_storage {
|
||||
trace!("Retracted child key {:?}", a);
|
||||
cache.lru_child_storage.remove(a);
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
}
|
||||
if clear {
|
||||
// We don't know anything about the block; clear everything
|
||||
trace!("Wiping cache");
|
||||
cache.lru_storage.clear();
|
||||
cache.lru_child_storage.clear();
|
||||
cache.lru_hashes.clear();
|
||||
cache.modifications.clear();
|
||||
}
|
||||
|
||||
let enacted: Vec<_> = enacted
|
||||
.iter()
|
||||
.filter(|h| commit_hash.as_ref().map_or(true, |p| *h != p))
|
||||
.cloned()
|
||||
.collect();
|
||||
cache.sync(&enacted, retracted);
|
||||
// Propagate cache only if committing on top of the latest canonical state
|
||||
// blocks are ordered by number and only one block with a given number is marked as canonical
|
||||
// (contributed to canonical state cache)
|
||||
|
||||
Reference in New Issue
Block a user