mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 08:11:04 +00:00
Multiple storage root support (#902)
* Implement a non generic version of child delta trie * Use delta_trie_root in state_machine * Expand InMemory backend to support multi-storage * Create Consolidate trait * Fix all crate compile and remove unused OverlayedChanges::drain * Implement child storage root support and overlay changes * Add child storage reader * Add child storage writer * Implement child storage cleaning * Fix light backend compile * Add all required ext functions for wasm executor * Add ext def to io * Add all io functions * Fix nostd compile * Add simple test * Remove unnecessary vec copy in child_storage_root_transaction * Use values_mut/for_each to make it shorter * Use extend to shorter a for loop * Move record_all_keys to trie so it's easier to generic them later * space -> tab * Remove to_owned in debug format * Clean out all to_owned * Break debug_trace to multiple lines * Remove 0.. * UserError copy/paste typo * Replace Vec::from_raw_parts by slice::from_raw_parts * Use iter::empty() * Wrap some long lines * Wrap a missing line * Remove unnecessary map https://github.com/paritytech/substrate/pull/856#discussion_r226222663 * Call ext_free after from_raw_parts * Fix tests in other crates
This commit is contained in:
@@ -17,11 +17,12 @@
|
||||
//! Conrete externalities implementation.
|
||||
|
||||
use std::{error, fmt, cmp::Ord};
|
||||
use backend::Backend;
|
||||
use backend::{Backend, Consolidate};
|
||||
use changes_trie::{Storage as ChangesTrieStorage, compute_changes_trie_root};
|
||||
use {Externalities, OverlayedChanges};
|
||||
use hash_db::Hasher;
|
||||
use substrate_trie::{MemoryDB, TrieDBMut, TrieMut};
|
||||
use primitives::storage::well_known_keys::is_child_storage_key;
|
||||
use substrate_trie::{MemoryDB, TrieDBMut, TrieMut, default_child_trie_root, is_child_trie_key_valid};
|
||||
use heapsize::HeapSizeOf;
|
||||
|
||||
const EXT_NOT_ALLOWED_TO_FAIL: &'static str = "Externalities not allowed to fail within runtime";
|
||||
@@ -122,6 +123,31 @@ where
|
||||
fn mark_dirty(&mut self) {
|
||||
self.storage_transaction = None;
|
||||
}
|
||||
|
||||
/// Fetch child storage root together with its transaction.
|
||||
fn child_storage_root_transaction(&mut self, storage_key: &[u8]) -> (Vec<u8>, B::Transaction) {
|
||||
self.mark_dirty();
|
||||
|
||||
let (root, transaction) = {
|
||||
let delta = self.overlay.committed.children.get(storage_key)
|
||||
.into_iter()
|
||||
.flat_map(|map| map.1.iter().map(|(k, v)| (k.clone(), v.clone())))
|
||||
.chain(self.overlay.prospective.children.get(storage_key)
|
||||
.into_iter()
|
||||
.flat_map(|map| map.1.iter().map(|(k, v)| (k.clone(), v.clone()))));
|
||||
|
||||
self.backend.child_storage_root(storage_key, delta)
|
||||
};
|
||||
|
||||
let root_val = if root == default_child_trie_root::<H>(storage_key) {
|
||||
None
|
||||
} else {
|
||||
Some(root.clone())
|
||||
};
|
||||
self.overlay.sync_child_storage_root(storage_key, root_val);
|
||||
|
||||
(root, transaction)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -137,8 +163,8 @@ where
|
||||
|
||||
self.backend.pairs().iter()
|
||||
.map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec())))
|
||||
.chain(self.overlay.committed.clone().into_iter().map(|(k, v)| (k, v.value)))
|
||||
.chain(self.overlay.prospective.clone().into_iter().map(|(k, v)| (k, v.value)))
|
||||
.chain(self.overlay.committed.top.clone().into_iter().map(|(k, v)| (k, v.value)))
|
||||
.chain(self.overlay.prospective.top.clone().into_iter().map(|(k, v)| (k, v.value)))
|
||||
.collect::<HashMap<_, _>>()
|
||||
.into_iter()
|
||||
.filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val)))
|
||||
@@ -158,6 +184,11 @@ where
|
||||
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL))
|
||||
}
|
||||
|
||||
fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
|
||||
self.overlay.child_storage(storage_key, key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
|
||||
self.backend.child_storage(storage_key, key).expect(EXT_NOT_ALLOWED_TO_FAIL))
|
||||
}
|
||||
|
||||
fn exists_storage(&self, key: &[u8]) -> bool {
|
||||
match self.overlay.storage(key) {
|
||||
Some(x) => x.is_some(),
|
||||
@@ -165,12 +196,52 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn exists_child_storage(&self, storage_key: &[u8], key: &[u8]) -> bool {
|
||||
match self.overlay.child_storage(storage_key, key) {
|
||||
Some(x) => x.is_some(),
|
||||
_ => self.backend.exists_child_storage(storage_key, key).expect(EXT_NOT_ALLOWED_TO_FAIL),
|
||||
}
|
||||
}
|
||||
|
||||
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>) {
|
||||
if is_child_storage_key(&key) {
|
||||
warn!(target: "trie", "Refuse to directly set child storage key");
|
||||
return;
|
||||
}
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.set_storage(key, value);
|
||||
}
|
||||
|
||||
fn place_child_storage(&mut self, storage_key: Vec<u8>, key: Vec<u8>, value: Option<Vec<u8>>) -> bool {
|
||||
if !is_child_storage_key(&storage_key) || !is_child_trie_key_valid::<H>(&storage_key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.set_child_storage(storage_key, key, value);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn kill_child_storage(&mut self, storage_key: &[u8]) {
|
||||
if !is_child_storage_key(storage_key) || !is_child_trie_key_valid::<H>(storage_key) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.clear_child_storage(storage_key);
|
||||
self.backend.for_keys_in_child_storage(storage_key, |key| {
|
||||
self.overlay.set_child_storage(storage_key.to_vec(), key.to_vec(), None);
|
||||
});
|
||||
}
|
||||
|
||||
fn clear_prefix(&mut self, prefix: &[u8]) {
|
||||
if is_child_storage_key(prefix) {
|
||||
warn!(target: "trie", "Refuse to directly clear prefix that is part of child storage key");
|
||||
return;
|
||||
}
|
||||
|
||||
self.mark_dirty();
|
||||
self.overlay.clear_prefix(prefix);
|
||||
self.backend.for_keys_with_prefix(prefix, |key| {
|
||||
@@ -183,19 +254,40 @@ where
|
||||
}
|
||||
|
||||
fn storage_root(&mut self) -> H::Out {
|
||||
if let Some((_, ref root)) = self.storage_transaction {
|
||||
if let Some((_, ref root)) = self.storage_transaction {
|
||||
return root.clone();
|
||||
}
|
||||
|
||||
// compute and memoize
|
||||
let delta = self.overlay.committed.iter().map(|(k, v)| (k.clone(), v.value.clone()))
|
||||
.chain(self.overlay.prospective.iter().map(|(k, v)| (k.clone(), v.value.clone())));
|
||||
let mut transaction = B::Transaction::default();
|
||||
let child_storage_keys: Vec<_> = self.overlay.prospective.children.keys().cloned().collect();
|
||||
|
||||
let (root, transaction) = self.backend.storage_root(delta);
|
||||
for key in child_storage_keys {
|
||||
let (_, t) = self.child_storage_root_transaction(&key);
|
||||
transaction.consolidate(t);
|
||||
}
|
||||
|
||||
// compute and memoize
|
||||
let delta = self.overlay.committed.top.iter().map(|(k, v)| (k.clone(), v.value.clone()))
|
||||
.chain(self.overlay.prospective.top.iter().map(|(k, v)| (k.clone(), v.value.clone())));
|
||||
|
||||
let (root, t) = self.backend.storage_root(delta);
|
||||
transaction.consolidate(t);
|
||||
self.storage_transaction = Some((transaction, root));
|
||||
root
|
||||
}
|
||||
|
||||
fn child_storage_root(&mut self, storage_key: &[u8]) -> Option<Vec<u8>> {
|
||||
if !is_child_storage_key(storage_key) || !is_child_trie_key_valid::<H>(storage_key) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.storage_transaction.is_some() {
|
||||
return Some(self.storage(storage_key).unwrap_or(default_child_trie_root::<H>(storage_key)));
|
||||
}
|
||||
|
||||
Some(self.child_storage_root_transaction(storage_key).0)
|
||||
}
|
||||
|
||||
fn storage_changes_root(&mut self, block: u64) -> Option<H::Out> {
|
||||
let root_and_tx = compute_changes_trie_root::<_, T, H>(
|
||||
self.backend,
|
||||
@@ -287,7 +379,7 @@ mod tests {
|
||||
#[test]
|
||||
fn storage_changes_root_is_some_when_extrinsic_changes_are_empty() {
|
||||
let mut overlay = prepare_overlay_with_changes();
|
||||
overlay.prospective.get_mut(&vec![1]).unwrap().value = None;
|
||||
overlay.prospective.top.get_mut(&vec![1]).unwrap().value = None;
|
||||
let storage = TestChangesTrieStorage::new();
|
||||
let backend = TestBackend::default();
|
||||
let mut ext = TestExt::new(&mut overlay, &backend, Some(&storage));
|
||||
|
||||
Reference in New Issue
Block a user