diff --git a/substrate/client/src/in_mem.rs b/substrate/client/src/in_mem.rs index 20b227e790..a63ea91e26 100644 --- a/substrate/client/src/in_mem.rs +++ b/substrate/client/src/in_mem.rs @@ -464,7 +464,7 @@ pub struct BlockImportOperation { pending_block: Option>, pending_cache: HashMap>, old_state: InMemoryBackend>, - new_state: Option>>, + new_state: Option<> as StateBackend>>::Transaction>, aux: Vec<(Vec, Option>)>, finalized_blocks: Vec<(BlockId, Option)>, set_head: Option>, @@ -502,7 +502,7 @@ impl backend::BlockImportOperation for BlockImportOperatio &mut self, update: > as StateBackend>>::Transaction, ) -> sp_blockchain::Result<()> { - self.new_state = Some(self.old_state.update(update)); + self.new_state = Some(update); Ok(()) } @@ -525,7 +525,7 @@ impl backend::BlockImportOperation for BlockImportOperatio child_delta ); - self.new_state = Some(InMemoryBackend::from(transaction)); + self.new_state = Some(transaction); Ok(root) } @@ -638,7 +638,12 @@ impl backend::Backend for Backend where Block::Hash let hash = header.hash(); - self.states.write().insert(hash, operation.new_state.unwrap_or_else(|| old_state.clone())); + let new_state = match operation.new_state { + Some(state) => old_state.update_backend(*header.state_root(), state), + None => old_state.clone(), + }; + + self.states.write().insert(hash, new_state); self.blockchain.insert(hash, header, justification, body, pending_block.state)?; } diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index 52ef068b3e..4c16b59160 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -615,7 +615,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("489ae9b57a19bb4733a264dc64bbcae9b140a904657a681ed3bb5fbbe8cf412b").into(), + state_root: hex!("409fb5a14aeb8b8c59258b503396a56dee45a0ee28a78de3e622db957425e275").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, diff --git a/substrate/primitives/state-machine/src/backend.rs b/substrate/primitives/state-machine/src/backend.rs index df8f810ceb..d45e822be8 100644 --- a/substrate/primitives/state-machine/src/backend.rs +++ b/substrate/primitives/state-machine/src/backend.rs @@ -16,12 +16,9 @@ //! State machine backends. These manage the code and storage of contracts. -use log::warn; use hash_db::Hasher; use codec::{Decode, Encode}; - use sp_core::{traits::RuntimeCode, storage::{ChildInfo, well_known_keys}}; -use sp_trie::{TrieMut, MemoryDB, trie_types::TrieDBMut}; use crate::{ trie_backend::TrieBackend, @@ -334,17 +331,20 @@ impl> Consolidate for sp_trie::GenericMem } /// Insert input pairs into memory db. -pub(crate) fn insert_into_memory_db(mdb: &mut MemoryDB, input: I) -> Option +#[cfg(test)] +pub(crate) fn insert_into_memory_db(mdb: &mut sp_trie::MemoryDB, input: I) -> Option where H: Hasher, I: IntoIterator, { + use sp_trie::{TrieMut, trie_types::TrieDBMut}; + let mut root = ::Out::default(); { let mut trie = TrieDBMut::::new(mdb, &mut root); for (key, value) in input { if let Err(e) = trie.insert(&key, &value) { - warn!(target: "trie", "Failed to write to trie: {}", e); + log::warn!(target: "trie", "Failed to write to trie: {}", e); return None; } } diff --git a/substrate/primitives/state-machine/src/basic.rs b/substrate/primitives/state-machine/src/basic.rs index 7f26085958..9eeba041d7 100644 --- a/substrate/primitives/state-machine/src/basic.rs +++ b/substrate/primitives/state-machine/src/basic.rs @@ -19,7 +19,7 @@ use std::{ collections::BTreeMap, any::{TypeId, Any}, iter::FromIterator, ops::Bound }; -use crate::{Backend, InMemoryBackend, StorageKey, StorageValue}; +use crate::{Backend, StorageKey, StorageValue}; use hash_db::Hasher; use sp_trie::{TrieConfiguration, empty_child_trie_root}; use sp_trie::trie_types::Layout; @@ -284,8 +284,7 @@ impl Externalities for BasicExternalities { ) -> Vec { if let Some(child) = self.inner.children_default.get(child_info.storage_key()) { let delta = child.data.clone().into_iter().map(|(k, v)| (k, Some(v))); - - InMemoryBackend::::default() + crate::in_memory_backend::new_in_mem::() .child_storage_root(&child.child_info, delta).0 } else { empty_child_trie_root::>() diff --git a/substrate/primitives/state-machine/src/in_memory_backend.rs b/substrate/primitives/state-machine/src/in_memory_backend.rs index 83126abbf7..8c0ae1ec8b 100644 --- a/substrate/primitives/state-machine/src/in_memory_backend.rs +++ b/substrate/primitives/state-machine/src/in_memory_backend.rs @@ -19,74 +19,60 @@ use crate::{ StorageKey, StorageValue, StorageCollection, trie_backend::TrieBackend, - backend::{Backend, insert_into_memory_db}, - stats::UsageInfo, }; -use std::{error, fmt, collections::{BTreeMap, HashMap}, marker::PhantomData, ops}; +use std::{collections::{BTreeMap, HashMap}}; use hash_db::Hasher; use sp_trie::{ - MemoryDB, child_trie_root, empty_child_trie_root, TrieConfiguration, trie_types::Layout, + MemoryDB, TrieMut, + trie_types::TrieDBMut, }; use codec::Codec; -use sp_core::storage::{ChildInfo, ChildType, Storage}; +use sp_core::storage::{ChildInfo, Storage}; -/// Error impossible. -// FIXME: use `!` type when stabilized. https://github.com/rust-lang/rust/issues/35121 -#[derive(Debug)] -pub enum Void {} - -impl fmt::Display for Void { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self {} - } -} - -impl error::Error for Void { - fn description(&self) -> &str { "unreachable error" } -} - -/// In-memory backend. Fully recomputes tries each time `as_trie_backend` is called but useful for -/// tests and proof checking. -pub struct InMemory { - inner: HashMap, BTreeMap>, - // This field is only needed for returning reference in `as_trie_backend`. - trie: Option, H>>, - _hasher: PhantomData, -} - -impl std::fmt::Debug for InMemory { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "InMemory ({} values)", self.inner.len()) - } -} - -impl Default for InMemory { - fn default() -> Self { - InMemory { - inner: Default::default(), - trie: None, - _hasher: PhantomData, +/// Insert input pairs into memory db. +fn insert_into_memory_db(mut root: H::Out, mdb: &mut MemoryDB, input: I) -> H::Out +where + H: Hasher, + I: IntoIterator)>, +{ + { + let mut trie = if root == Default::default() { + TrieDBMut::::new(mdb, &mut root) + } else { + TrieDBMut::::from_existing(mdb, &mut root).unwrap() + }; + for (key, value) in input { + if let Err(e) = match value { + Some(value) => { + trie.insert(&key, &value) + }, + None => { + trie.remove(&key) + }, + } { + panic!("Failed to write to trie: {}", e); + } } + trie.commit(); } + root } -impl Clone for InMemory { - fn clone(&self) -> Self { - InMemory { - inner: self.inner.clone(), - trie: None, - _hasher: PhantomData, - } - } +/// Create a new empty instance of in-memory backend. +pub fn new_in_mem() -> TrieBackend, H> +where + H::Out: Codec + Ord, +{ + let db = MemoryDB::default(); + let mut backend = TrieBackend::new(db, Default::default()); + backend.insert(std::iter::empty()); + backend } -impl PartialEq for InMemory { - fn eq(&self, other: &Self) -> bool { - self.inner.eq(&other.inner) - } -} - -impl InMemory { +impl TrieBackend, H> +where + H::Out: Codec + Ord, +{ /// Copy the state, with applied updates pub fn update< T: IntoIterator, StorageCollection)> @@ -94,59 +80,117 @@ impl InMemory { &self, changes: T, ) -> Self { - let mut inner = self.inner.clone(); - for (child_info, key_values) in changes.into_iter() { - let entry = inner.entry(child_info).or_default(); - for (key, val) in key_values { - match val { - Some(v) => { entry.insert(key, v); }, - None => { entry.remove(&key); }, - } + let mut clone = self.clone(); + clone.insert(changes); + clone + } + + /// Insert values into backend trie. + pub fn insert< + T: IntoIterator, StorageCollection)> + >( + &mut self, + changes: T, + ) { + let mut new_child_roots = Vec::new(); + let mut root_map = None; + let root = self.root().clone(); + for (child_info, map) in changes { + if let Some(child_info) = child_info.as_ref() { + let prefix_storage_key = child_info.prefixed_storage_key(); + let ch = insert_into_memory_db::(root, self.backend_storage_mut(), map.clone().into_iter()); + new_child_roots.push((prefix_storage_key.into_inner(), Some(ch.as_ref().into()))); + } else { + root_map = Some(map); } } - inner.into() + + let root = match root_map { + Some(map) => insert_into_memory_db::( + root, + self.backend_storage_mut(), + map.clone().into_iter().chain(new_child_roots.into_iter()), + ), + None => insert_into_memory_db::( + root, + self.backend_storage_mut(), + new_child_roots.into_iter(), + ), + }; + self.essence.set_root(root); + } + + /// Merge trie nodes into this backend. + pub fn update_backend(&self, root: H::Out, changes: MemoryDB) -> Self { + let mut clone = self.backend_storage().clone(); + clone.consolidate(changes); + Self::new(clone, root) + } + + /// Compare with another in-memory backend. + pub fn eq(&self, other: &Self) -> bool { + self.root() == other.root() + } +} + +impl Clone for TrieBackend, H> +where + H::Out: Codec + Ord, +{ + fn clone(&self) -> Self { + TrieBackend::new(self.backend_storage().clone(), self.root().clone()) + } +} + +impl Default for TrieBackend, H> +where + H::Out: Codec + Ord, +{ + fn default() -> Self { + new_in_mem() } } impl From, BTreeMap>> - for InMemory + for TrieBackend, H> +where + H::Out: Codec + Ord, { fn from(inner: HashMap, BTreeMap>) -> Self { - InMemory { - inner, - trie: None, - _hasher: PhantomData, - } + let mut backend = new_in_mem(); + backend.insert(inner.into_iter().map(|(k, m)| (k, m.into_iter().map(|(k, v)| (k, Some(v))).collect()))); + backend } } -impl From for InMemory { +impl From for TrieBackend, H> +where + H::Out: Codec + Ord, +{ fn from(inners: Storage) -> Self { let mut inner: HashMap, BTreeMap> = inners.children_default.into_iter().map(|(_k, c)| (Some(c.child_info), c.data)).collect(); inner.insert(None, inners.top); - InMemory { - inner, - trie: None, - _hasher: PhantomData, - } + inner.into() } } -impl From> for InMemory { +impl From> for TrieBackend, H> +where + H::Out: Codec + Ord, +{ fn from(inner: BTreeMap) -> Self { let mut expanded = HashMap::new(); expanded.insert(None, inner); - InMemory { - inner: expanded, - trie: None, - _hasher: PhantomData, - } + expanded.into() } } impl From, StorageCollection)>> - for InMemory { + for TrieBackend, H> +where + H::Out: Codec + Ord, +{ fn from( inner: Vec<(Option, StorageCollection)>, ) -> Self { @@ -164,213 +208,16 @@ impl From, StorageCollection)>> } } -impl InMemory { - /// Child storage infos iterator. - pub fn child_storage_infos(&self) -> impl Iterator { - self.inner.iter().filter_map(|item| item.0.as_ref()) - } -} - -impl Backend for InMemory where H::Out: Codec { - type Error = Void; - type Transaction = Vec<( - Option, - StorageCollection, - )>; - type TrieBackendStorage = MemoryDB; - - fn storage(&self, key: &[u8]) -> Result, Self::Error> { - Ok(self.inner.get(&None).and_then(|map| map.get(key).map(Clone::clone))) - } - - fn child_storage( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result, Self::Error> { - Ok(self.inner.get(&Some(child_info.to_owned())) - .and_then(|map| map.get(key).map(Clone::clone))) - } - - fn exists_storage(&self, key: &[u8]) -> Result { - Ok(self.inner.get(&None).map(|map| map.get(key).is_some()).unwrap_or(false)) - } - - fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { - self.inner.get(&None) - .map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f)); - } - - fn for_key_values_with_prefix(&self, prefix: &[u8], mut f: F) { - self.inner.get(&None).map(|map| map.iter().filter(|(key, _val)| key.starts_with(prefix)) - .for_each(|(k, v)| f(k, v))); - } - - fn for_keys_in_child_storage( - &self, - child_info: &ChildInfo, - mut f: F, - ) { - self.inner.get(&Some(child_info.to_owned())) - .map(|map| map.keys().for_each(|k| f(&k))); - } - - fn for_child_keys_with_prefix( - &self, - child_info: &ChildInfo, - prefix: &[u8], - f: F, - ) { - self.inner.get(&Some(child_info.to_owned())) - .map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f)); - } - - fn storage_root(&self, delta: I) -> (H::Out, Self::Transaction) - where - I: IntoIterator, Option>)>, - ::Out: Ord, - { - let existing_pairs = self.inner.get(&None) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), Some(v.clone())))); - - let transaction: Vec<_> = delta.into_iter().collect(); - let root = Layout::::trie_root(existing_pairs.chain(transaction.iter().cloned()) - .collect::>() - .into_iter() - .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) - ); - - let full_transaction = transaction.into_iter().collect(); - - (root, vec![(None, full_transaction)]) - } - - fn child_storage_root( - &self, - child_info: &ChildInfo, - delta: I, - ) -> (H::Out, bool, Self::Transaction) - where - I: IntoIterator, Option>)>, - H::Out: Ord - { - let child_type = child_info.child_type(); - let child_info = Some(child_info.to_owned()); - - let existing_pairs = self.inner.get(&child_info) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), Some(v.clone())))); - - let transaction: Vec<_> = delta.into_iter().collect(); - let root = child_trie_root::, _, _, _>( - existing_pairs.chain(transaction.iter().cloned()) - .collect::>() - .into_iter() - .filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val))) - ); - - let full_transaction = transaction.into_iter().collect(); - - let is_default = match child_type { - ChildType::ParentKeyId => root == empty_child_trie_root::>(), - }; - - (root, is_default, vec![(child_info, full_transaction)]) - } - - fn next_storage_key(&self, key: &[u8]) -> Result, Self::Error> { - let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded); - let next_key = self.inner.get(&None) - .and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()); - - Ok(next_key) - } - - fn next_child_storage_key( - &self, - child_info: &ChildInfo, - key: &[u8], - ) -> Result, Self::Error> { - let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded); - let next_key = self.inner.get(&Some(child_info.to_owned())) - .and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()); - - Ok(next_key) - } - - fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { - self.inner.get(&None) - .into_iter() - .flat_map(|map| map.iter().map(|(k, v)| (k.clone(), v.clone()))) - .collect() - } - - fn keys(&self, prefix: &[u8]) -> Vec { - self.inner.get(&None) - .into_iter() - .flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned()) - .collect() - } - - fn child_keys( - &self, - child_info: &ChildInfo, - prefix: &[u8], - ) -> Vec { - self.inner.get(&Some(child_info.to_owned())) - .into_iter() - .flat_map(|map| map.keys().filter(|k| k.starts_with(prefix)).cloned()) - .collect() - } - - fn as_trie_backend(&mut self)-> Option<&TrieBackend> { - let mut mdb = MemoryDB::default(); - let mut new_child_roots = Vec::new(); - let mut root_map = None; - for (child_info, map) in &self.inner { - if let Some(child_info) = child_info.as_ref() { - let prefix_storage_key = child_info.prefixed_storage_key(); - let ch = insert_into_memory_db::(&mut mdb, map.clone().into_iter())?; - new_child_roots.push((prefix_storage_key.into_inner(), ch.as_ref().into())); - } else { - root_map = Some(map); - } - } - let root = match root_map { - Some(map) => insert_into_memory_db::( - &mut mdb, - map.clone().into_iter().chain(new_child_roots.into_iter()), - )?, - None => insert_into_memory_db::( - &mut mdb, - new_child_roots.into_iter(), - )?, - }; - self.trie = Some(TrieBackend::new(mdb, root)); - self.trie.as_ref() - } - - fn register_overlay_stats(&mut self, _stats: &crate::stats::StateMachineStats) { } - - fn usage_info(&self) -> UsageInfo { - UsageInfo::empty() - } - - fn wipe(&self) -> Result<(), Self::Error> { - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; use sp_runtime::traits::BlakeTwo256; + use crate::backend::Backend; /// Assert in memory backend with only child trie keys works as trie backend. #[test] fn in_memory_with_child_trie_only() { - let storage = InMemory::::default(); + let storage = new_in_mem::(); let child_info = ChildInfo::new_default(b"1"); let child_info = &child_info; let mut storage = storage.update( diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 83bc812b15..2ff10d4aff 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -72,7 +72,7 @@ pub use proving_backend::{ pub use trie_backend_essence::{TrieBackendStorage, Storage}; pub use trie_backend::TrieBackend; pub use error::{Error, ExecutionError}; -pub use in_memory_backend::InMemory as InMemoryBackend; +pub use in_memory_backend::new_in_mem; pub use stats::{UsageInfo, UsageUnit, StateMachineStats}; pub use sp_core::traits::CloneableSpawn; @@ -87,6 +87,9 @@ pub type ChangesTrieTransaction = ( ChangesTrieCacheAction<::Out, N>, ); +/// Trie backend with in-memory storage. +pub type InMemoryBackend = TrieBackend, H>; + /// Strategy for executing a call into the runtime. #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ExecutionStrategy { @@ -1001,7 +1004,7 @@ mod tests { fn set_child_storage_works() { let child_info = ChildInfo::new_default(b"sub1"); let child_info = &child_info; - let mut state = InMemoryBackend::::default(); + let mut state = new_in_mem::(); let backend = state.as_trie_backend().unwrap(); let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); diff --git a/substrate/primitives/state-machine/src/proving_backend.rs b/substrate/primitives/state-machine/src/proving_backend.rs index deafeb902d..1cb281b070 100644 --- a/substrate/primitives/state-machine/src/proving_backend.rs +++ b/substrate/primitives/state-machine/src/proving_backend.rs @@ -391,9 +391,10 @@ mod tests { ]; let in_memory = InMemoryBackend::::default(); let mut in_memory = in_memory.update(contents); + let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()]; let in_memory_root = in_memory.full_storage_root::<_, Vec<_>, _>( ::std::iter::empty(), - in_memory.child_storage_infos().map(|k|(k.to_owned(), Vec::new())) + child_storage_keys.into_iter().map(|k|(k.to_owned(), Vec::new())) ).0; (0..64).for_each(|i| assert_eq!( in_memory.storage(&[i]).unwrap().unwrap(), diff --git a/substrate/primitives/state-machine/src/testing.rs b/substrate/primitives/state-machine/src/testing.rs index 70a96c623a..5993ef5db6 100644 --- a/substrate/primitives/state-machine/src/testing.rs +++ b/substrate/primitives/state-machine/src/testing.rs @@ -41,7 +41,7 @@ use sp_externalities::{Extensions, Extension}; /// Simple HashMap-based Externalities impl. pub struct TestExternalities where - H::Out: codec::Codec, + H::Out: codec::Codec + Ord, { overlay: OverlayedChanges, storage_transaction_cache: StorageTransactionCache< @@ -113,7 +113,7 @@ impl TestExternalities /// Insert key/value into backend pub fn insert(&mut self, k: StorageKey, v: StorageValue) { - self.backend = self.backend.update(vec![(None, vec![(k, Some(v))])]); + self.backend.insert(vec![(None, vec![(k, Some(v))])]); } /// Registers the given extension for this instance. @@ -157,7 +157,7 @@ impl TestExternalities } impl std::fmt::Debug for TestExternalities - where H::Out: codec::Codec, + where H::Out: Ord + codec::Codec, { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs()) @@ -193,7 +193,7 @@ impl From for TestExternalities sp_externalities::ExtensionStore for TestExternalities where H: Hasher, - H::Out: codec::Codec, + H::Out: Ord + codec::Codec, N: ChangesTrieBlockNumber, { fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { @@ -230,7 +230,7 @@ mod tests { ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); - const ROOT: [u8; 32] = hex!("2a340d3dfd52f5992c6b117e9e45f479e6da5afffafeb26ab619cf137a95aeb8"); + const ROOT: [u8; 32] = hex!("555d4777b52e9196e3f6373c556cc661e79cd463f881ab9e921e70fc30144bf4"); assert_eq!(&ext.storage_root()[..], &ROOT); } diff --git a/substrate/primitives/state-machine/src/trie_backend.rs b/substrate/primitives/state-machine/src/trie_backend.rs index 08eea29360..81fa020245 100644 --- a/substrate/primitives/state-machine/src/trie_backend.rs +++ b/substrate/primitives/state-machine/src/trie_backend.rs @@ -29,7 +29,7 @@ use crate::{ /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher> { - essence: TrieBackendEssence, + pub (crate) essence: TrieBackendEssence, } impl, H: Hasher> TrieBackend where H::Out: Codec { @@ -50,6 +50,11 @@ impl, H: Hasher> TrieBackend where H::Out: Codec self.essence.backend_storage() } + /// Get backend storage reference. + pub fn backend_storage_mut(&mut self) -> &mut S { + self.essence.backend_storage_mut() + } + /// Get trie root. pub fn root(&self) -> &H::Out { self.essence.root() @@ -179,6 +184,7 @@ impl, H: Hasher> Backend for TrieBackend where &mut write_overlay, ); + let delta: Vec<_> = delta.into_iter().collect(); match delta_trie_root::, _, _, _, _>(&mut eph, root, delta) { Ok(ret) => root = ret, Err(e) => warn!(target: "trie", "Failed to write to trie: {}", e), @@ -243,6 +249,10 @@ impl, H: Hasher> Backend for TrieBackend where fn usage_info(&self) -> crate::UsageInfo { crate::UsageInfo::empty() } + + fn wipe(&self) -> Result<(), Self::Error> { + Ok(()) + } } #[cfg(test)] diff --git a/substrate/primitives/state-machine/src/trie_backend_essence.rs b/substrate/primitives/state-machine/src/trie_backend_essence.rs index 28d1c68ca2..4622297ec0 100644 --- a/substrate/primitives/state-machine/src/trie_backend_essence.rs +++ b/substrate/primitives/state-machine/src/trie_backend_essence.rs @@ -55,11 +55,21 @@ impl, H: Hasher> TrieBackendEssence where H::Out: &self.storage } + /// Get backend storage reference. + pub fn backend_storage_mut(&mut self) -> &mut S { + &mut self.storage + } + /// Get trie root. pub fn root(&self) -> &H::Out { &self.root } + /// Set trie root. This is useful for testing. + pub fn set_root(&mut self, root: H::Out) { + self.root = root; + } + /// Consumes self and returns underlying storage. pub fn into_storage(self) -> S { self.storage