diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index 37db59416f..3b985ec2b9 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -18,19 +18,13 @@ //! Trie-based state machine backend. use crate::{ - debug, - trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}, - warn, Backend, StorageKey, StorageValue, + trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, + Backend, StorageKey, StorageValue, }; -use codec::{Codec, Decode}; +use codec::Codec; use hash_db::Hasher; -use sp_core::storage::{ChildInfo, ChildType, StateVersion}; -use sp_std::{boxed::Box, vec::Vec}; -use sp_trie::{ - child_delta_trie_root, delta_trie_root, empty_child_trie_root, - trie_types::{TrieDB, TrieError}, - LayoutV0, LayoutV1, Trie, -}; +use sp_core::storage::{ChildInfo, StateVersion}; +use sp_std::vec::Vec; /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher> { @@ -144,43 +138,11 @@ where } fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { - let collect_all = || -> Result<_, Box>> { - let trie = TrieDB::::new(self.essence(), self.essence.root())?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, value) = x?; - v.push((key.to_vec(), value.to_vec())); - } - - Ok(v) - }; - - match collect_all() { - Ok(v) => v, - Err(e) => { - debug!(target: "trie", "Error extracting trie values: {}", e); - Vec::new() - }, - } + self.essence.pairs() } fn keys(&self, prefix: &[u8]) -> Vec { - let collect_all = || -> Result<_, Box>> { - let trie = TrieDB::::new(self.essence(), self.essence.root())?; - let mut v = Vec::new(); - for x in trie.iter()? { - let (key, _) = x?; - if key.starts_with(prefix) { - v.push(key.to_vec()); - } - } - - Ok(v) - }; - - collect_all() - .map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)) - .unwrap_or_default() + self.essence.keys(prefix) } fn storage_root<'a>( @@ -191,25 +153,7 @@ where where H::Out: Ord, { - let mut write_overlay = S::Overlay::default(); - let mut root = *self.essence.root(); - - { - let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - let res = match state_version { - StateVersion::V0 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), - StateVersion::V1 => - delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), - }; - - match res { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), - } - } - - (root, write_overlay) + self.essence.storage_root(delta, state_version) } fn child_storage_root<'a>( @@ -221,45 +165,7 @@ where where H::Out: Ord, { - let default_root = match child_info.child_type() { - ChildType::ParentKeyId => empty_child_trie_root::>(), - }; - let mut write_overlay = S::Overlay::default(); - let prefixed_storage_key = child_info.prefixed_storage_key(); - let mut root = match self.storage(prefixed_storage_key.as_slice()) { - Ok(value) => value - .and_then(|r| Decode::decode(&mut &r[..]).ok()) - .unwrap_or_else(|| default_root.clone()), - Err(e) => { - warn!(target: "trie", "Failed to read child storage root: {}", e); - default_root.clone() - }, - }; - - { - let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay); - match match state_version { - StateVersion::V0 => child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - root, - delta, - ), - StateVersion::V1 => child_delta_trie_root::, _, _, _, _, _, _>( - child_info.keyspace(), - &mut eph, - root, - delta, - ), - } { - Ok(ret) => root = ret, - Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), - } - } - - let is_default = root == default_root; - - (root, is_default, write_overlay) + self.essence.child_storage_root(child_info, delta, state_version) } fn as_trie_backend(&self) -> Option<&TrieBackend> { diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index 8f3c27f03c..e33e50641b 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -23,10 +23,11 @@ use codec::Encode; use hash_db::{self, AsHashDB, HashDB, HashDBRef, Hasher, Prefix}; #[cfg(feature = "std")] use parking_lot::RwLock; -use sp_core::storage::ChildInfo; +use sp_core::storage::{ChildInfo, ChildType, StateVersion}; use sp_std::{boxed::Box, vec::Vec}; use sp_trie::{ - empty_child_trie_root, read_child_trie_value, read_trie_value, + child_delta_trie_root, delta_trie_root, empty_child_trie_root, read_child_trie_value, + read_trie_value, trie_types::{TrieDB, TrieError}, DBValue, KeySpacedDB, PrefixedMemoryDB, Trie, TrieDBIterator, TrieDBKeyIterator, }; @@ -58,12 +59,12 @@ pub trait Storage: Send + Sync { /// Local cache for child root. #[cfg(feature = "std")] -pub(crate) struct Cache { - pub child_root: HashMap, Option>>, +pub(crate) struct Cache { + pub child_root: HashMap, Option>, } #[cfg(feature = "std")] -impl Cache { +impl Cache { fn new() -> Self { Cache { child_root: HashMap::new() } } @@ -75,7 +76,7 @@ pub struct TrieBackendEssence, H: Hasher> { root: H::Out, empty: H::Out, #[cfg(feature = "std")] - pub(crate) cache: Arc>, + pub(crate) cache: Arc>>, } impl, H: Hasher> TrieBackendEssence @@ -130,22 +131,26 @@ where } /// Access the root of the child storage in its parent trie - fn child_root(&self, child_info: &ChildInfo) -> Result> { + fn child_root(&self, child_info: &ChildInfo) -> Result> { #[cfg(feature = "std")] { if let Some(result) = self.cache.read().child_root.get(child_info.storage_key()) { - return Ok(result.clone()) + return Ok(*result) } } - let result = self.storage(child_info.prefixed_storage_key().as_slice())?; + let result = self.storage(child_info.prefixed_storage_key().as_slice())?.map(|r| { + let mut hash = H::Out::default(); + + // root is fetched from DB, not writable by runtime, so it's always valid. + hash.as_mut().copy_from_slice(&r[..]); + + hash + }); #[cfg(feature = "std")] { - self.cache - .write() - .child_root - .insert(child_info.storage_key().to_vec(), result.clone()); + self.cache.write().child_root.insert(child_info.storage_key().to_vec(), result); } Ok(result) @@ -163,15 +168,7 @@ where None => return Ok(None), }; - let mut hash = H::Out::default(); - - if child_root.len() != hash.as_ref().len() { - return Err(format!("Invalid child storage hash at {:?}", child_info.storage_key())) - } - // note: child_root and hash must be same size, panics otherwise. - hash.as_mut().copy_from_slice(&child_root[..]); - - self.next_storage_key_from_root(&hash, Some(child_info), key) + self.next_storage_key_from_root(&child_root, Some(child_info), key) } /// Return next key from main trie or child trie by providing corresponding root. @@ -231,9 +228,10 @@ where child_info: &ChildInfo, key: &[u8], ) -> Result> { - let root = self - .child_root(child_info)? - .unwrap_or_else(|| empty_child_trie_root::>().encode()); + let root = match self.child_root(child_info)? { + Some(root) => root, + None => return Ok(None), + }; let map_e = |e| format!("Trie lookup error: {}", e); @@ -253,19 +251,13 @@ where f: impl FnMut(Vec, Vec) -> bool, allow_missing_nodes: bool, ) -> Result { - let mut child_root; let root = if let Some(child_info) = child_info.as_ref() { - if let Some(fetched_child_root) = self.child_root(child_info)? { - child_root = H::Out::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - child_root.as_mut().copy_from_slice(fetched_child_root.as_slice()); - - &child_root - } else { - return Ok(true) + match self.child_root(child_info)? { + Some(child_root) => child_root, + None => return Ok(true), } } else { - &self.root + self.root }; self.trie_iter_inner(&root, prefix, f, child_info, start_at, allow_missing_nodes) @@ -279,22 +271,21 @@ where prefix: Option<&[u8]>, mut f: F, ) { - let mut child_root = H::Out::default(); let root = if let Some(child_info) = child_info.as_ref() { - let root_vec = match self.child_root(child_info) { - Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::>().encode()), + match self.child_root(child_info) { + Ok(Some(v)) => v, + // If the child trie doesn't exist, there is no need to continue. + Ok(None) => return, Err(e) => { debug!(target: "trie", "Error while iterating child storage: {}", e); return }, - }; - child_root.as_mut().copy_from_slice(&root_vec); - &child_root + } } else { - &self.root + self.root }; - self.trie_iter_key_inner(root, prefix, |k| f(k), child_info) + self.trie_iter_key_inner(&root, prefix, |k| f(k), child_info) } /// Execute given closure for all keys starting with prefix. @@ -304,15 +295,16 @@ where prefix: &[u8], mut f: impl FnMut(&[u8]), ) { - let root_vec = match self.child_root(child_info) { - Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::>().encode()), + let root = match self.child_root(child_info) { + Ok(Some(v)) => v, + // If the child trie doesn't exist, there is no need to continue. + Ok(None) => return, Err(e) => { debug!(target: "trie", "Error while iterating child storage: {}", e); return }, }; - let mut root = H::Out::default(); - root.as_mut().copy_from_slice(&root_vec); + self.trie_iter_key_inner( &root, Some(prefix), @@ -438,6 +430,130 @@ where false, ); } + + /// Returns all `(key, value)` pairs in the trie. + pub fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { + let collect_all = || -> sp_std::result::Result<_, Box>> { + let trie = TrieDB::::new(self, &self.root)?; + let mut v = Vec::new(); + for x in trie.iter()? { + let (key, value) = x?; + v.push((key.to_vec(), value.to_vec())); + } + + Ok(v) + }; + + match collect_all() { + Ok(v) => v, + Err(e) => { + debug!(target: "trie", "Error extracting trie values: {}", e); + Vec::new() + }, + } + } + + /// Returns all keys that start with the given `prefix`. + pub fn keys(&self, prefix: &[u8]) -> Vec { + let collect_all = || -> sp_std::result::Result<_, Box>> { + let trie = TrieDB::::new(self, &self.root)?; + let mut v = Vec::new(); + for x in trie.iter()? { + let (key, _) = x?; + if key.starts_with(prefix) { + v.push(key.to_vec()); + } + } + + Ok(v) + }; + + collect_all() + .map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)) + .unwrap_or_default() + } + + /// Return the storage root after applying the given `delta`. + pub fn storage_root<'a>( + &self, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (H::Out, S::Overlay) + where + H::Out: Ord, + { + let mut write_overlay = S::Overlay::default(); + let mut root = self.root; + + { + let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); + let res = match state_version { + StateVersion::V0 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + StateVersion::V1 => + delta_trie_root::, _, _, _, _, _>(&mut eph, root, delta), + }; + + match res { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + } + } + + (root, write_overlay) + } + + /// Returns the child storage root for the child trie `child_info` after applying the given + /// `delta`. + pub fn child_storage_root<'a>( + &self, + child_info: &ChildInfo, + delta: impl Iterator)>, + state_version: StateVersion, + ) -> (H::Out, bool, S::Overlay) + where + H::Out: Ord, + { + let default_root = match child_info.child_type() { + ChildType::ParentKeyId => empty_child_trie_root::>(), + }; + let mut write_overlay = S::Overlay::default(); + let mut root = match self.child_root(child_info) { + Ok(Some(hash)) => hash, + Ok(None) => default_root, + Err(e) => { + warn!(target: "trie", "Failed to read child storage root: {}", e); + default_root.clone() + }, + }; + + { + let mut eph = Ephemeral::new(self.backend_storage(), &mut write_overlay); + match match state_version { + StateVersion::V0 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + StateVersion::V1 => + child_delta_trie_root::, _, _, _, _, _, _>( + child_info.keyspace(), + &mut eph, + root, + delta, + ), + } { + Ok(ret) => root = ret, + Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), + } + } + + let is_default = root == default_root; + + (root, is_default, write_overlay) + } } pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> { diff --git a/substrate/primitives/trie/src/lib.rs b/substrate/primitives/trie/src/lib.rs index f598615be9..c4d4c7210b 100644 --- a/substrate/primitives/trie/src/lib.rs +++ b/substrate/primitives/trie/src/lib.rs @@ -374,18 +374,14 @@ where pub fn read_child_trie_value( keyspace: &[u8], db: &DB, - root_slice: &[u8], + root: &TrieHash, key: &[u8], ) -> Result>, Box>> where DB: hash_db::HashDBRef, { - let mut root = TrieHash::::default(); - // root is fetched from DB, not writable by runtime, so it's always valid. - root.as_mut().copy_from_slice(root_slice); - let db = KeySpacedDB::new(&*db, keyspace); - TrieDB::::new(&db, &root)?.get(key).map(|x| x.map(|val| val.to_vec())) + TrieDB::::new(&db, root)?.get(key).map(|x| x.map(|val| val.to_vec())) } /// Read a value from the child trie with given query.