mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 09:37:55 +00:00
Allow updating configuration of changes tries (#3201)
* DigestItem::ChangesTrieSignal * introduce changes_trie::State * introduce config activation block * ChangesTrieSignal::as_new_configuration * moved well_known_cache_keys to client * extracted DbChangesTrieStorage to separate file * change meaning of none in blockchain cache * changes trie config (FULL) cache draft * eliminating const ChangesTrieConfiguration * delay pruning * continue elimination * do not prune CT config from cache * removed redundant code * fix some TODOs * introduce ConfigurationRange * use Configuration range in build * build skewed digest * remove debug print * extracted surface iterator * key_changes works with skewed digests * fix client build * add test for NeverPrune * fix TODO * fixed some TODOs * more tests * fixing TODOs * fixed compilation * update runtime version * git rid of large tuple * too long lines * config_activation_block -> zero * obsolete TODO * removed unjustified expect * update TODOs with issue number * new CT pruning algorithm fixed cache + multiple blocks finalization track CT configuraiton on light clients support CT configuration change revert revert CT config test new CT pruning algorithm fixed cache + multiple blocks finalization track CT configuraiton on light clients support CT configuration change revert revert CT config test * BlockIdOrHeader isn't really required * removed debug leftovers + some docs * more docs * more post-merge fixes * more post-merge fixes * revertes some unnecessary changes * reverted unnecessary changes * fix compilation + unnecessary changes * (restart CI) * fix cache update when finalizing multiple blocks * fixed tests * collect_extrinsics -> set_collect_extrinsics * restore lost test * do not calculate block number twice * Update primitives/blockchain/src/error.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * map_err -> unwrap_or * document get_at Result * delete abandoned file * added weight for set_changes_trie_config * prefer_configs -> fail_if_disabled * Update client/api/src/backend.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * Update client/db/src/changes_tries_storage.rs Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * CommitOperation+merge -> CommitOperations * fixed test compilation * merged two different CTRange structs * lost file * uggrade db from v0 to v1 (init CT cache + add column) * fix after merge Co-authored-by: cheme <emericchevalier.pro@gmail.com> Co-authored-by: Gavin Wood <github@gavwood.com>
This commit is contained in:
committed by
Gavin Wood
parent
45fbf09dac
commit
febf29390a
Vendored
+88
-62
@@ -16,7 +16,7 @@
|
||||
|
||||
//! DB-backed cache of blockchain data.
|
||||
|
||||
use std::{sync::Arc, collections::HashMap};
|
||||
use std::{sync::Arc, collections::{HashMap, hash_map::Entry}};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use kvdb::{KeyValueDB, DBTransaction};
|
||||
@@ -51,8 +51,10 @@ pub enum EntryType {
|
||||
/// Block identifier that holds both hash and number.
|
||||
#[derive(Clone, Debug, Encode, Decode, PartialEq)]
|
||||
pub struct ComplexBlockId<Block: BlockT> {
|
||||
hash: Block::Hash,
|
||||
number: NumberFor<Block>,
|
||||
/// Hash of the block.
|
||||
pub(crate) hash: Block::Hash,
|
||||
/// Number of the block.
|
||||
pub(crate) number: NumberFor<Block>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> ComplexBlockId<Block> {
|
||||
@@ -79,7 +81,7 @@ pub struct DbCache<Block: BlockT> {
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
key_lookup_column: u32,
|
||||
header_column: u32,
|
||||
authorities_column: u32,
|
||||
cache_column: u32,
|
||||
genesis_hash: Block::Hash,
|
||||
best_finalized_block: ComplexBlockId<Block>,
|
||||
}
|
||||
@@ -90,7 +92,7 @@ impl<Block: BlockT> DbCache<Block> {
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
key_lookup_column: u32,
|
||||
header_column: u32,
|
||||
authorities_column: u32,
|
||||
cache_column: u32,
|
||||
genesis_hash: Block::Hash,
|
||||
best_finalized_block: ComplexBlockId<Block>,
|
||||
) -> Self {
|
||||
@@ -99,7 +101,7 @@ impl<Block: BlockT> DbCache<Block> {
|
||||
db,
|
||||
key_lookup_column,
|
||||
header_column,
|
||||
authorities_column,
|
||||
cache_column,
|
||||
genesis_hash,
|
||||
best_finalized_block,
|
||||
}
|
||||
@@ -115,30 +117,48 @@ impl<Block: BlockT> DbCache<Block> {
|
||||
DbCacheTransaction {
|
||||
cache: self,
|
||||
tx,
|
||||
cache_at_op: HashMap::new(),
|
||||
cache_at_ops: HashMap::new(),
|
||||
best_finalized_block: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Begin cache transaction with given ops.
|
||||
pub fn transaction_with_ops<'a>(
|
||||
&'a mut self,
|
||||
tx: &'a mut DBTransaction,
|
||||
ops: DbCacheTransactionOps<Block>,
|
||||
) -> DbCacheTransaction<'a, Block> {
|
||||
DbCacheTransaction {
|
||||
cache: self,
|
||||
tx,
|
||||
cache_at_ops: ops.cache_at_ops,
|
||||
best_finalized_block: ops.best_finalized_block,
|
||||
}
|
||||
}
|
||||
|
||||
/// Run post-commit cache operations.
|
||||
pub fn commit(&mut self, ops: DbCacheTransactionOps<Block>) {
|
||||
for (name, op) in ops.cache_at_op.into_iter() {
|
||||
self.get_cache(name).on_transaction_commit(op);
|
||||
pub fn commit(&mut self, ops: DbCacheTransactionOps<Block>) -> ClientResult<()> {
|
||||
for (name, ops) in ops.cache_at_ops.into_iter() {
|
||||
self.get_cache(name)?.on_transaction_commit(ops);
|
||||
}
|
||||
if let Some(best_finalized_block) = ops.best_finalized_block {
|
||||
self.best_finalized_block = best_finalized_block;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates `ListCache` with the given name or returns a reference to the existing.
|
||||
fn get_cache(&mut self, name: CacheKeyId) -> &mut ListCache<Block, Vec<u8>, self::list_storage::DbStorage> {
|
||||
pub(crate) fn get_cache(
|
||||
&mut self,
|
||||
name: CacheKeyId,
|
||||
) -> ClientResult<&mut ListCache<Block, Vec<u8>, self::list_storage::DbStorage>> {
|
||||
get_cache_helper(
|
||||
&mut self.cache_at,
|
||||
name,
|
||||
&self.db,
|
||||
self.key_lookup_column,
|
||||
self.header_column,
|
||||
self.authorities_column,
|
||||
self.cache_column,
|
||||
&self.best_finalized_block
|
||||
)
|
||||
}
|
||||
@@ -154,34 +174,49 @@ fn get_cache_helper<'a, Block: BlockT>(
|
||||
header: u32,
|
||||
cache: u32,
|
||||
best_finalized_block: &ComplexBlockId<Block>,
|
||||
) -> &'a mut ListCache<Block, Vec<u8>, self::list_storage::DbStorage> {
|
||||
cache_at.entry(name).or_insert_with(|| {
|
||||
ListCache::new(
|
||||
self::list_storage::DbStorage::new(name.to_vec(), db.clone(),
|
||||
self::list_storage::DbColumns {
|
||||
meta: COLUMN_META,
|
||||
key_lookup,
|
||||
header,
|
||||
cache,
|
||||
},
|
||||
),
|
||||
cache_pruning_strategy(name),
|
||||
best_finalized_block.clone(),
|
||||
)
|
||||
})
|
||||
) -> ClientResult<&'a mut ListCache<Block, Vec<u8>, self::list_storage::DbStorage>> {
|
||||
match cache_at.entry(name) {
|
||||
Entry::Occupied(entry) => Ok(entry.into_mut()),
|
||||
Entry::Vacant(entry) => {
|
||||
let cache = ListCache::new(
|
||||
self::list_storage::DbStorage::new(name.to_vec(), db.clone(),
|
||||
self::list_storage::DbColumns {
|
||||
meta: COLUMN_META,
|
||||
key_lookup,
|
||||
header,
|
||||
cache,
|
||||
},
|
||||
),
|
||||
cache_pruning_strategy(name),
|
||||
best_finalized_block.clone(),
|
||||
)?;
|
||||
Ok(entry.insert(cache))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Cache operations that are to be committed after database transaction is committed.
|
||||
#[derive(Default)]
|
||||
pub struct DbCacheTransactionOps<Block: BlockT> {
|
||||
cache_at_op: HashMap<CacheKeyId, self::list_cache::CommitOperation<Block, Vec<u8>>>,
|
||||
cache_at_ops: HashMap<CacheKeyId, self::list_cache::CommitOperations<Block, Vec<u8>>>,
|
||||
best_finalized_block: Option<ComplexBlockId<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> DbCacheTransactionOps<Block> {
|
||||
/// Empty transaction ops.
|
||||
pub fn empty() -> DbCacheTransactionOps<Block> {
|
||||
DbCacheTransactionOps {
|
||||
cache_at_ops: HashMap::new(),
|
||||
best_finalized_block: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Database-backed blockchain data cache transaction valid for single block import.
|
||||
pub struct DbCacheTransaction<'a, Block: BlockT> {
|
||||
cache: &'a mut DbCache<Block>,
|
||||
tx: &'a mut DBTransaction,
|
||||
cache_at_op: HashMap<CacheKeyId, self::list_cache::CommitOperation<Block, Vec<u8>>>,
|
||||
cache_at_ops: HashMap<CacheKeyId, self::list_cache::CommitOperations<Block, Vec<u8>>>,
|
||||
best_finalized_block: Option<ComplexBlockId<Block>>,
|
||||
}
|
||||
|
||||
@@ -189,7 +224,7 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
/// Convert transaction into post-commit operations set.
|
||||
pub fn into_ops(self) -> DbCacheTransactionOps<Block> {
|
||||
DbCacheTransactionOps {
|
||||
cache_at_op: self.cache_at_op,
|
||||
cache_at_ops: self.cache_at_ops,
|
||||
best_finalized_block: self.best_finalized_block,
|
||||
}
|
||||
}
|
||||
@@ -202,8 +237,6 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
data_at: HashMap<CacheKeyId, Vec<u8>>,
|
||||
entry_type: EntryType,
|
||||
) -> ClientResult<Self> {
|
||||
assert!(self.cache_at_op.is_empty());
|
||||
|
||||
// prepare list of caches that are not update
|
||||
// (we might still need to do some cache maintenance in this case)
|
||||
let missed_caches = self.cache.cache_at.keys()
|
||||
@@ -212,8 +245,9 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut insert_op = |name: CacheKeyId, value: Option<Vec<u8>>| -> Result<(), sp_blockchain::Error> {
|
||||
let cache = self.cache.get_cache(name);
|
||||
let op = cache.on_block_insert(
|
||||
let cache = self.cache.get_cache(name)?;
|
||||
let cache_ops = self.cache_at_ops.entry(name).or_default();
|
||||
cache.on_block_insert(
|
||||
&mut self::list_storage::DbStorageTransaction::new(
|
||||
cache.storage(),
|
||||
&mut self.tx,
|
||||
@@ -222,10 +256,9 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
block.clone(),
|
||||
value,
|
||||
entry_type,
|
||||
cache_ops,
|
||||
)?;
|
||||
if let Some(op) = op {
|
||||
self.cache_at_op.insert(name, op);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
@@ -245,23 +278,19 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
pub fn on_block_finalize(
|
||||
mut self,
|
||||
parent: ComplexBlockId<Block>,
|
||||
block: ComplexBlockId<Block>
|
||||
block: ComplexBlockId<Block>,
|
||||
) -> ClientResult<Self> {
|
||||
assert!(self.cache_at_op.is_empty());
|
||||
|
||||
for (name, cache_at) in self.cache.cache_at.iter() {
|
||||
let op = cache_at.on_block_finalize(
|
||||
for (name, cache) in self.cache.cache_at.iter() {
|
||||
let cache_ops = self.cache_at_ops.entry(*name).or_default();
|
||||
cache.on_block_finalize(
|
||||
&mut self::list_storage::DbStorageTransaction::new(
|
||||
cache_at.storage(),
|
||||
cache.storage(),
|
||||
&mut self.tx
|
||||
),
|
||||
parent.clone(),
|
||||
block.clone(),
|
||||
cache_ops,
|
||||
)?;
|
||||
|
||||
if let Some(op) = op {
|
||||
self.cache_at_op.insert(name.to_owned(), op);
|
||||
}
|
||||
}
|
||||
|
||||
self.best_finalized_block = Some(block);
|
||||
@@ -275,16 +304,15 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
|
||||
reverted_block: &ComplexBlockId<Block>,
|
||||
) -> ClientResult<Self> {
|
||||
for (name, cache) in self.cache.cache_at.iter() {
|
||||
let op = cache.on_block_revert(
|
||||
let cache_ops = self.cache_at_ops.entry(*name).or_default();
|
||||
cache.on_block_revert(
|
||||
&mut self::list_storage::DbStorageTransaction::new(
|
||||
cache.storage(),
|
||||
&mut self.tx
|
||||
),
|
||||
reverted_block,
|
||||
cache_ops,
|
||||
)?;
|
||||
|
||||
assert!(!self.cache_at_op.contains_key(name));
|
||||
self.cache_at_op.insert(name.to_owned(), op);
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
@@ -310,7 +338,7 @@ impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
|
||||
)?;
|
||||
let tx_ops = tx.into_ops();
|
||||
db.write(dbtx).map_err(db_err)?;
|
||||
cache.commit(tx_ops);
|
||||
cache.commit(tx_ops)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -318,40 +346,38 @@ impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
|
||||
&self,
|
||||
key: &CacheKeyId,
|
||||
at: &BlockId<Block>,
|
||||
) -> Option<((NumberFor<Block>, Block::Hash), Option<(NumberFor<Block>, Block::Hash)>, Vec<u8>)> {
|
||||
) -> ClientResult<Option<((NumberFor<Block>, Block::Hash), Option<(NumberFor<Block>, Block::Hash)>, Vec<u8>)>> {
|
||||
let mut cache = self.0.write();
|
||||
let storage = cache.get_cache(*key).storage();
|
||||
let cache = cache.get_cache(*key)?;
|
||||
let storage = cache.storage();
|
||||
let db = storage.db();
|
||||
let columns = storage.columns();
|
||||
let at = match *at {
|
||||
BlockId::Hash(hash) => {
|
||||
let header = utils::read_header::<Block>(
|
||||
let header = utils::require_header::<Block>(
|
||||
&**db,
|
||||
columns.key_lookup,
|
||||
columns.header,
|
||||
BlockId::Hash(hash.clone())).ok()??;
|
||||
BlockId::Hash(hash.clone()))?;
|
||||
ComplexBlockId::new(hash, *header.number())
|
||||
},
|
||||
BlockId::Number(number) => {
|
||||
let hash = utils::read_header::<Block>(
|
||||
let hash = utils::require_header::<Block>(
|
||||
&**db,
|
||||
columns.key_lookup,
|
||||
columns.header,
|
||||
BlockId::Number(number.clone())).ok()??.hash();
|
||||
BlockId::Number(number.clone()))?.hash();
|
||||
ComplexBlockId::new(hash, number)
|
||||
},
|
||||
};
|
||||
|
||||
cache.cache_at
|
||||
.get(key)?
|
||||
.value_at_block(&at)
|
||||
cache.value_at_block(&at)
|
||||
.map(|block_and_value| block_and_value.map(|(begin_block, end_block, value)|
|
||||
(
|
||||
(begin_block.number, begin_block.hash),
|
||||
end_block.map(|end_block| (end_block.number, end_block.hash)),
|
||||
value,
|
||||
)))
|
||||
.ok()?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user