mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 10:31:04 +00:00
Fix key collision for child trie (#4162)
* In progress, runtime io must switch to future proof root + child_specific (unique id) + u32 type. * Switch interface, sr-io seems ok, rpc could use similar interface to sr-io, genesis json broken if there is child trie in existing encoding genesis. * test from previous implementation. * fix proving test. * Restore Keyspacedb from other branch, only apply to child trie. * Removing unneeded child_info from child root (child info are stored if things changed, otherwhise the root does not change). * Switch rpc to use same format as ext: more future proof. * use root from child info for trie backend essence. * Breaking long lines. * Update doc and clean pr a bit. * fix error type * Restore removed doc on merge and update sr-io doc. * Switch child storage api to use directly unique id, if managed id where to be put in place, the api will change at this time. * Clean deprecated host interface from child. * Removing assertion on child info (can fail depending on root memoization). * merging child info in the overlay when possible. * child iteration by prefix using child_info. * Using ChainInfo in frame support. ChainInfo gets redesign to avoid buffers allocation on every calls. * Add length of root to the data of child info. * comments * Encode compact. * Remove child info with root. * Fix try_update condition. * Comment Ext child root caching. * Replace tuples by struct with field * remove StorageTuple alias. * Fix doc tests, and remove StorageOverlay and ChildStorageOverlay aliases.
This commit is contained in:
@@ -24,8 +24,9 @@ mod node_codec;
|
||||
mod trie_stream;
|
||||
|
||||
use sp_std::boxed::Box;
|
||||
use sp_std::marker::PhantomData;
|
||||
use sp_std::vec::Vec;
|
||||
use hash_db::Hasher;
|
||||
use hash_db::{Hasher, Prefix};
|
||||
/// Our `NodeCodec`-specific error.
|
||||
pub use error::Error;
|
||||
/// The Substrate format implementation of `TrieStream`.
|
||||
@@ -191,6 +192,7 @@ pub fn child_trie_root<L: TrieConfiguration, I, A, B>(
|
||||
/// but a generic implementation may ignore this type parameter and use other hashers.
|
||||
pub fn child_delta_trie_root<L: TrieConfiguration, I, A, B, DB, RD>(
|
||||
_storage_key: &[u8],
|
||||
keyspace: &[u8],
|
||||
db: &mut DB,
|
||||
root_data: RD,
|
||||
delta: I,
|
||||
@@ -208,7 +210,8 @@ pub fn child_delta_trie_root<L: TrieConfiguration, I, A, B, DB, RD>(
|
||||
root.as_mut().copy_from_slice(root_data.as_ref());
|
||||
|
||||
{
|
||||
let mut trie = TrieDBMut::<L>::from_existing(&mut *db, &mut root)?;
|
||||
let mut db = KeySpacedDBMut::new(&mut *db, keyspace);
|
||||
let mut trie = TrieDBMut::<L>::from_existing(&mut db, &mut root)?;
|
||||
|
||||
for (key, change) in delta {
|
||||
match change {
|
||||
@@ -224,6 +227,7 @@ pub fn child_delta_trie_root<L: TrieConfiguration, I, A, B, DB, RD>(
|
||||
/// Call `f` for all keys in a child trie.
|
||||
pub fn for_keys_in_child_trie<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
|
||||
_storage_key: &[u8],
|
||||
keyspace: &[u8],
|
||||
db: &DB,
|
||||
root_slice: &[u8],
|
||||
mut f: F
|
||||
@@ -236,7 +240,8 @@ pub fn for_keys_in_child_trie<L: TrieConfiguration, F: FnMut(&[u8]), DB>(
|
||||
// root is fetched from DB, not writable by runtime, so it's always valid.
|
||||
root.as_mut().copy_from_slice(root_slice);
|
||||
|
||||
let trie = TrieDB::<L>::new(&*db, &root)?;
|
||||
let db = KeySpacedDB::new(&*db, keyspace);
|
||||
let trie = TrieDB::<L>::new(&db, &root)?;
|
||||
let iter = trie.iter()?;
|
||||
|
||||
for x in iter {
|
||||
@@ -273,6 +278,7 @@ pub fn record_all_keys<L: TrieConfiguration, DB>(
|
||||
/// Read a value from the child trie.
|
||||
pub fn read_child_trie_value<L: TrieConfiguration, DB>(
|
||||
_storage_key: &[u8],
|
||||
keyspace: &[u8],
|
||||
db: &DB,
|
||||
root_slice: &[u8],
|
||||
key: &[u8]
|
||||
@@ -285,12 +291,14 @@ pub fn read_child_trie_value<L: TrieConfiguration, DB>(
|
||||
// root is fetched from DB, not writable by runtime, so it's always valid.
|
||||
root.as_mut().copy_from_slice(root_slice);
|
||||
|
||||
Ok(TrieDB::<L>::new(&*db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?)
|
||||
let db = KeySpacedDB::new(&*db, keyspace);
|
||||
Ok(TrieDB::<L>::new(&db, &root)?.get(key).map(|x| x.map(|val| val.to_vec()))?)
|
||||
}
|
||||
|
||||
/// Read a value from the child trie with given query.
|
||||
pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=DBValue>, DB>(
|
||||
_storage_key: &[u8],
|
||||
keyspace: &[u8],
|
||||
db: &DB,
|
||||
root_slice: &[u8],
|
||||
key: &[u8],
|
||||
@@ -304,7 +312,104 @@ pub fn read_child_trie_value_with<L: TrieConfiguration, Q: Query<L::Hash, Item=D
|
||||
// root is fetched from DB, not writable by runtime, so it's always valid.
|
||||
root.as_mut().copy_from_slice(root_slice);
|
||||
|
||||
Ok(TrieDB::<L>::new(&*db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?)
|
||||
let db = KeySpacedDB::new(&*db, keyspace);
|
||||
Ok(TrieDB::<L>::new(&db, &root)?.get_with(key, query).map(|x| x.map(|val| val.to_vec()))?)
|
||||
}
|
||||
|
||||
/// `HashDB` implementation that append a encoded prefix (unique id bytes) in addition to the
|
||||
/// prefix of every key value.
|
||||
pub struct KeySpacedDB<'a, DB, H>(&'a DB, &'a [u8], PhantomData<H>);
|
||||
|
||||
/// `HashDBMut` implementation that append a encoded prefix (unique id bytes) in addition to the
|
||||
/// prefix of every key value.
|
||||
///
|
||||
/// Mutable variant of `KeySpacedDB`, see [`KeySpacedDB`].
|
||||
pub struct KeySpacedDBMut<'a, DB, H>(&'a mut DB, &'a [u8], PhantomData<H>);
|
||||
|
||||
/// Utility function used to merge some byte data (keyspace) and `prefix` data
|
||||
/// before calling key value database primitives.
|
||||
fn keyspace_as_prefix_alloc(ks: &[u8], prefix: Prefix) -> (Vec<u8>, Option<u8>) {
|
||||
let mut result = sp_std::vec![0; ks.len() + prefix.0.len()];
|
||||
result[..ks.len()].copy_from_slice(ks);
|
||||
result[ks.len()..].copy_from_slice(prefix.0);
|
||||
(result, prefix.1)
|
||||
}
|
||||
|
||||
impl<'a, DB, H> KeySpacedDB<'a, DB, H> where
|
||||
H: Hasher,
|
||||
{
|
||||
/// instantiate new keyspaced db
|
||||
pub fn new(db: &'a DB, ks: &'a [u8]) -> Self {
|
||||
KeySpacedDB(db, ks, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DB, H> KeySpacedDBMut<'a, DB, H> where
|
||||
H: Hasher,
|
||||
{
|
||||
/// instantiate new keyspaced db
|
||||
pub fn new(db: &'a mut DB, ks: &'a [u8]) -> Self {
|
||||
KeySpacedDBMut(db, ks, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DB, H, T> hash_db::HashDBRef<H, T> for KeySpacedDB<'a, DB, H> where
|
||||
DB: hash_db::HashDBRef<H, T>,
|
||||
H: Hasher,
|
||||
T: From<&'static [u8]>,
|
||||
{
|
||||
fn get(&self, key: &H::Out, prefix: Prefix) -> Option<T> {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.get(key, (&derived_prefix.0, derived_prefix.1))
|
||||
}
|
||||
|
||||
fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.contains(key, (&derived_prefix.0, derived_prefix.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DB, H, T> hash_db::HashDB<H, T> for KeySpacedDBMut<'a, DB, H> where
|
||||
DB: hash_db::HashDB<H, T>,
|
||||
H: Hasher,
|
||||
T: Default + PartialEq<T> + for<'b> From<&'b [u8]> + Clone + Send + Sync,
|
||||
{
|
||||
fn get(&self, key: &H::Out, prefix: Prefix) -> Option<T> {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.get(key, (&derived_prefix.0, derived_prefix.1))
|
||||
}
|
||||
|
||||
fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.contains(key, (&derived_prefix.0, derived_prefix.1))
|
||||
}
|
||||
|
||||
fn insert(&mut self, prefix: Prefix, value: &[u8]) -> H::Out {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.insert((&derived_prefix.0, derived_prefix.1), value)
|
||||
}
|
||||
|
||||
fn emplace(&mut self, key: H::Out, prefix: Prefix, value: T) {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.emplace(key, (&derived_prefix.0, derived_prefix.1), value)
|
||||
}
|
||||
|
||||
fn remove(&mut self, key: &H::Out, prefix: Prefix) {
|
||||
let derived_prefix = keyspace_as_prefix_alloc(self.1, prefix);
|
||||
self.0.remove(key, (&derived_prefix.0, derived_prefix.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, DB, H, T> hash_db::AsHashDB<H, T> for KeySpacedDBMut<'a, DB, H> where
|
||||
DB: hash_db::HashDB<H, T>,
|
||||
H: Hasher,
|
||||
T: Default + PartialEq<T> + for<'b> From<&'b [u8]> + Clone + Send + Sync,
|
||||
{
|
||||
fn as_hash_db(&self) -> &dyn hash_db::HashDB<H, T> { &*self }
|
||||
|
||||
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, T> + 'b) {
|
||||
&mut *self
|
||||
}
|
||||
}
|
||||
|
||||
/// Constants used into trie simplification codec.
|
||||
|
||||
Reference in New Issue
Block a user