diff --git a/Cargo.lock b/Cargo.lock index 9f29feece6d86..b0a9d4fcb5547 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8426,7 +8426,6 @@ version = "0.8.0-rc6" dependencies = [ "hash-db", "hex-literal", - "itertools 0.9.0", "log", "num-traits", "parity-scale-codec", @@ -8438,6 +8437,7 @@ dependencies = [ "sp-externalities", "sp-panic-handler", "sp-runtime", + "sp-std", "sp-trie", "trie-db", "trie-root", @@ -8835,6 +8835,7 @@ dependencies = [ "sp-consensus-aura", "sp-consensus-babe", "sp-core", + "sp-externalities", "sp-finality-grandpa", "sp-inherents", "sp-io", diff --git a/primitives/externalities/Cargo.toml b/primitives/externalities/Cargo.toml index 17184ca69402f..952912bee592c 100644 --- a/primitives/externalities/Cargo.toml +++ b/primitives/externalities/Cargo.toml @@ -13,7 +13,16 @@ documentation = "https://docs.rs/sp-externalities" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -sp-storage = { version = "2.0.0-rc6", path = "../storage" } -sp-std = { version = "2.0.0-rc6", path = "../std" } -environmental = { version = "1.1.1" } -codec = { package = "parity-scale-codec", version = "1.3.1" } +sp-storage = { version = "2.0.0-rc6", path = "../storage", default-features = false } +sp-std = { version = "2.0.0-rc6", path = "../std", default-features = false } +environmental = { version = "1.1.1", default-features = false } +codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "environmental/std", + "sp-std/std", + "sp-storage/std", +] diff --git a/primitives/externalities/src/extensions.rs b/primitives/externalities/src/extensions.rs index 08d81e46c88fc..d79f99d3344ea 100644 --- a/primitives/externalities/src/extensions.rs +++ b/primitives/externalities/src/extensions.rs @@ -22,7 +22,9 @@ //! //! It is required that each extension implements the [`Extension`] trait. -use std::{collections::HashMap, collections::hash_map::Entry, any::{Any, TypeId}, ops::DerefMut}; +use sp_std::{ + collections::btree_map::{BTreeMap, Entry}, any::{Any, TypeId}, ops::DerefMut, boxed::Box, +}; use crate::Error; /// Marker trait for types that should be registered as [`Externalities`](crate::Externalities) extension. @@ -104,9 +106,10 @@ pub trait ExtensionStore { /// Stores extensions that should be made available through the externalities. #[derive(Default)] pub struct Extensions { - extensions: HashMap>, + extensions: BTreeMap>, } +#[cfg(feature = "std")] impl std::fmt::Debug for Extensions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Extensions: ({})", self.extensions.len()) diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index 01570e0bfadd3..388482964f18c 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![cfg_attr(not(feature = "std"), no_std)] + //! Substrate externalities abstraction //! //! The externalities mainly provide access to storage and to registered extensions. Extensions @@ -23,7 +25,7 @@ //! //! This crate exposes the main [`Externalities`] trait. -use std::any::{Any, TypeId}; +use sp_std::{any::{Any, TypeId}, vec::Vec, boxed::Box}; use sp_storage::{ChildInfo, TrackedStorageKey}; diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 88d3b5a75c156..f34fabdd88908 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -13,20 +13,20 @@ documentation = "https://docs.rs/sp-state-machine" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -log = "0.4.8" -parking_lot = "0.10.0" -hash-db = "0.15.2" -trie-db = "0.22.0" -trie-root = "0.16.0" -sp-trie = { version = "2.0.0-rc6", path = "../trie" } -sp-core = { version = "2.0.0-rc6", path = "../core" } -sp-panic-handler = { version = "2.0.0-rc6", path = "../panic-handler" } -codec = { package = "parity-scale-codec", version = "1.3.1" } -num-traits = "0.2.8" -rand = "0.7.2" -sp-externalities = { version = "0.8.0-rc6", path = "../externalities" } -itertools = "0.9" +log = { version = "0.4.8", optional = true } +parking_lot = { version = "0.10.0", optional = true } +hash-db = { version = "0.15.2", default-features = false } +trie-db = { version = "0.22.0", default-features = false } +trie-root = { version = "0.16.0", default-features = false } +sp-trie = { version = "2.0.0-rc6", path = "../trie", default-features = false } +sp-core = { version = "2.0.0-rc6", path = "../core", default-features = false } +sp-panic-handler = { version = "2.0.0-rc6", path = "../panic-handler", optional = true } +codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false } +num-traits = { version = "0.2.8", default-features = false } +rand = { version = "0.7.2", optional = true } +sp-externalities = { version = "0.8.0-rc6", path = "../externalities", default-features = false } smallvec = "1.4.1" +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../std" } [dev-dependencies] hex-literal = "0.3.1" @@ -34,4 +34,19 @@ sp-runtime = { version = "2.0.0-rc6", path = "../runtime" } pretty_assertions = "0.6.1" [features] -default = [] +default = ["std"] +std = [ + "codec/std", + "hash-db/std", + "num-traits/std", + "sp-core/std", + "sp-externalities/std", + "sp-std/std", + "sp-trie/std", + "trie-db/std", + "trie-root/std", + "log", + "parking_lot", + "rand", + "sp-panic-handler", +] diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index 6ced5ed0e521e..360fe9a985682 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -20,7 +20,6 @@ use hash_db::Hasher; use codec::{Decode, Encode}; use sp_core::{ - traits::RuntimeCode, storage::{ChildInfo, well_known_keys, TrackedStorageKey} }; use crate::{ @@ -28,12 +27,15 @@ use crate::{ trie_backend_essence::TrieBackendStorage, UsageInfo, StorageKey, StorageValue, StorageCollection, ChildStorageCollection, }; +use sp_std::vec::Vec; +#[cfg(feature = "std")] +use sp_core::traits::RuntimeCode; /// A state backend is used to read state data and can have changes committed /// to it. /// /// The clone operation (if implemented) should be cheap. -pub trait Backend: std::fmt::Debug { +pub trait Backend: sp_std::fmt::Debug { /// An error type when fetching data is not possible. type Error: super::Error; @@ -375,11 +377,13 @@ pub(crate) fn insert_into_memory_db(mdb: &mut sp_trie::MemoryDB, input: } /// Wrapper to create a [`RuntimeCode`] from a type that implements [`Backend`]. +#[cfg(feature = "std")] pub struct BackendRuntimeCode<'a, B, H> { backend: &'a B, _marker: std::marker::PhantomData, } +#[cfg(feature = "std")] impl<'a, B: Backend, H: Hasher> sp_core::traits::FetchRuntimeCode for BackendRuntimeCode<'a, B, H> { @@ -388,6 +392,7 @@ impl<'a, B: Backend, H: Hasher> sp_core::traits::FetchRuntimeCode for } } +#[cfg(feature = "std")] impl<'a, B: Backend, H: Hasher> BackendRuntimeCode<'a, B, H> where H::Out: Encode { /// Create a new instance. pub fn new(backend: &'a B) -> Self { diff --git a/primitives/state-machine/src/changes_trie/build.rs b/primitives/state-machine/src/changes_trie/build.rs index 675904578be97..b23481411ae27 100644 --- a/primitives/state-machine/src/changes_trie/build.rs +++ b/primitives/state-machine/src/changes_trie/build.rs @@ -140,8 +140,15 @@ fn prepare_extrinsics_input_inner<'a, B, H, Number>( Number: BlockNumber, { changes - .filter(|( _, v)| v.extrinsics().next().is_some()) - .try_fold(BTreeMap::new(), |mut map: BTreeMap<&[u8], (ExtrinsicIndex, Vec)>, (k, v)| { + .filter_map(|(k, v)| { + let extrinsics = v.extrinsics(); + if !extrinsics.is_empty() { + Some((k, extrinsics)) + } else { + None + } + }) + .try_fold(BTreeMap::new(), |mut map: BTreeMap<&[u8], (ExtrinsicIndex, Vec)>, (k, extrinsics)| { match map.entry(k) { Entry::Vacant(entry) => { // ignore temporary values (values that have null value at the end of operation @@ -161,7 +168,7 @@ fn prepare_extrinsics_input_inner<'a, B, H, Number>( } }; - let extrinsics = v.extrinsics().cloned().collect(); + let extrinsics = extrinsics.into_iter().collect(); entry.insert((ExtrinsicIndex { block: block.clone(), key: k.to_vec(), @@ -170,11 +177,11 @@ fn prepare_extrinsics_input_inner<'a, B, H, Number>( Entry::Occupied(mut entry) => { // we do not need to check for temporary values here, because entry is Occupied // AND we are checking it before insertion - let extrinsics = &mut entry.get_mut().1; - extrinsics.extend( - v.extrinsics().cloned() + let entry_extrinsics = &mut entry.get_mut().1; + entry_extrinsics.extend( + extrinsics.into_iter() ); - extrinsics.sort(); + entry_extrinsics.sort(); }, } diff --git a/primitives/state-machine/src/changes_trie/mod.rs b/primitives/state-machine/src/changes_trie/mod.rs index 04322f1d5930c..fd7b38c052f9e 100644 --- a/primitives/state-machine/src/changes_trie/mod.rs +++ b/primitives/state-machine/src/changes_trie/mod.rs @@ -85,9 +85,6 @@ use crate::{ }, }; -/// Changes that are made outside of extrinsics are marked with this index; -pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff; - /// Requirements for block number that can be used with changes tries. pub trait BlockNumber: Send + Sync + 'static + diff --git a/primitives/state-machine/src/error.rs b/primitives/state-machine/src/error.rs index 5468262f54a2c..489f6e6666001 100644 --- a/primitives/state-machine/src/error.rs +++ b/primitives/state-machine/src/error.rs @@ -17,7 +17,7 @@ /// State Machine Errors -use std::fmt; +use sp_std::fmt; /// State Machine Error bound. /// @@ -34,7 +34,7 @@ impl Error for T {} #[derive(Debug, Eq, PartialEq)] pub enum ExecutionError { /// Backend error. - Backend(String), + Backend(crate::DefaultError), /// The entry `:code` doesn't exist in storage so there's no way we can execute anything. CodeEntryDoesNotExist, /// Backend is incompatible with execution proof generation process. diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index e36964716f8c9..e9259f9a10bc1 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -18,23 +18,28 @@ //! Concrete externalities implementation. use crate::{ - StorageKey, StorageValue, OverlayedChanges, StorageTransactionCache, + StorageKey, StorageValue, OverlayedChanges, backend::Backend, - changes_trie::State as ChangesTrieState, }; - use hash_db::Hasher; use sp_core::{ - offchain::storage::OffchainOverlayedChanges, storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey}, - traits::Externalities, hexdisplay::HexDisplay, + hexdisplay::HexDisplay, }; use sp_trie::{trie_types::Layout, empty_child_trie_root}; -use sp_externalities::{Extensions, Extension}; +use sp_externalities::{Externalities, Extensions, Extension, + ExtensionStore}; use codec::{Decode, Encode, EncodeAppend}; -use std::{error, fmt, any::{Any, TypeId}}; -use log::{warn, trace}; +use sp_std::{fmt, any::{Any, TypeId}, vec::Vec, vec, boxed::Box}; +use crate::{warn, trace, log_error}; +#[cfg(feature = "std")] +use sp_core::offchain::storage::OffchainOverlayedChanges; +#[cfg(feature = "std")] +use crate::changes_trie::State as ChangesTrieState; +use crate::StorageTransactionCache; +#[cfg(feature = "std")] +use std::error; const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime"; const BENCHMARKING_FN: &str = "\ @@ -42,7 +47,19 @@ const BENCHMARKING_FN: &str = "\ For that reason client started transactions before calling into runtime are not allowed. Without client transactions the loop condition garantuees the success of the tx close."; + +#[cfg(feature = "std")] +fn guard() -> sp_panic_handler::AbortGuard { + sp_panic_handler::AbortGuard::force_abort() +} + +#[cfg(not(feature = "std"))] +fn guard() -> () { + () +} + /// Errors that can occur when interacting with the externalities. +#[cfg(feature = "std")] #[derive(Debug, Copy, Clone)] pub enum Error { /// Failure to load state data from the backend. @@ -53,6 +70,7 @@ pub enum Error { Executor(E), } +#[cfg(feature = "std")] impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -62,6 +80,7 @@ impl fmt::Display for Error { } } +#[cfg(feature = "std")] impl error::Error for Error { fn description(&self) -> &str { match *self { @@ -81,30 +100,49 @@ pub struct Ext<'a, H, N, B> /// The overlayed changes to write to. overlay: &'a mut OverlayedChanges, /// The overlayed changes destined for the Offchain DB. + #[cfg(feature = "std")] offchain_overlay: &'a mut OffchainOverlayedChanges, /// The storage backend to read from. backend: &'a B, /// The cache for the storage transactions. storage_transaction_cache: &'a mut StorageTransactionCache, /// Changes trie state to read from. + #[cfg(feature = "std")] changes_trie_state: Option>, /// Pseudo-unique id used for tracing. pub id: u16, /// Dummy usage of N arg. - _phantom: std::marker::PhantomData, + _phantom: sp_std::marker::PhantomData, /// Extensions registered with this instance. + #[cfg(feature = "std")] extensions: Option<&'a mut Extensions>, } + impl<'a, H, N, B> Ext<'a, H, N, B> -where - H: Hasher, - H::Out: Ord + 'static + codec::Codec, - B: 'a + Backend, - N: crate::changes_trie::BlockNumber, + where + H: Hasher, + B: Backend, + N: crate::changes_trie::BlockNumber, { + /// Create a new `Ext`. + #[cfg(not(feature = "std"))] + pub fn new( + overlay: &'a mut OverlayedChanges, + storage_transaction_cache: &'a mut StorageTransactionCache, + backend: &'a B, + ) -> Self { + Ext { + overlay, + backend, + id: 0, + storage_transaction_cache, + _phantom: Default::default(), + } + } /// Create a new `Ext` from overlayed changes and read-only backend + #[cfg(feature = "std")] pub fn new( overlay: &'a mut OverlayedChanges, offchain_overlay: &'a mut OffchainOverlayedChanges, @@ -133,6 +171,7 @@ where } /// Read only accessor for the scheduled overlay changes. + #[cfg(feature = "std")] pub fn get_offchain_storage_changes(&self) -> &OffchainOverlayedChanges { &*self.offchain_overlay } @@ -159,14 +198,14 @@ where } } -impl<'a, H, B, N> Externalities for Ext<'a, H, N, B> +impl<'a, H, N, B> Externalities for Ext<'a, H, N, B> where H: Hasher, H::Out: Ord + 'static + codec::Codec, - B: 'a + Backend, + B: Backend, N: crate::changes_trie::BlockNumber, { - + #[cfg(feature = "std")] fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>) { use ::sp_core::offchain::STORAGE_PREFIX; match value { @@ -175,8 +214,11 @@ where } } + #[cfg(not(feature = "std"))] + fn set_offchain_storage(&mut self, _key: &[u8], _value: Option<&[u8]>) {} + fn storage(&self, key: &[u8]) -> Option { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(|| self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)); trace!(target: "state", "{:04x}: Get {}={:?}", @@ -188,7 +230,7 @@ where } fn storage_hash(&self, key: &[u8]) -> Option> { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = self.overlay .storage(key) .map(|x| x.map(|x| H::hash(x))) @@ -207,7 +249,7 @@ where child_info: &ChildInfo, key: &[u8], ) -> Option { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = self.overlay .child_storage(child_info, key) .map(|x| x.map(|x| x.to_vec())) @@ -231,7 +273,7 @@ where child_info: &ChildInfo, key: &[u8], ) -> Option> { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = self.overlay .child_storage(child_info, key) .map(|x| x.map(|x| H::hash(x))) @@ -251,7 +293,7 @@ where } fn exists_storage(&self, key: &[u8]) -> bool { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = match self.overlay.storage(key) { Some(x) => x.is_some(), _ => self.backend.exists_storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL), @@ -271,7 +313,7 @@ where child_info: &ChildInfo, key: &[u8], ) -> bool { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let result = match self.overlay.child_storage(child_info, key) { Some(x) => x.is_some(), @@ -337,7 +379,7 @@ where HexDisplay::from(&key), value.as_ref().map(HexDisplay::from) ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); if is_child_storage_key(&key) { warn!(target: "trie", "Refuse to directly set child storage key"); return; @@ -359,7 +401,7 @@ where HexDisplay::from(&key), value.as_ref().map(HexDisplay::from) ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); self.mark_dirty(); self.overlay.set_child_storage(child_info, key, value); @@ -373,7 +415,7 @@ where self.id, HexDisplay::from(&child_info.storage_key()), ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); self.mark_dirty(); self.overlay.clear_child_storage(child_info); @@ -387,7 +429,7 @@ where self.id, HexDisplay::from(&prefix), ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); if is_child_storage_key(prefix) { warn!(target: "trie", "Refuse to directly clear prefix that is part of child storage key"); return; @@ -410,7 +452,7 @@ where HexDisplay::from(&child_info.storage_key()), HexDisplay::from(&prefix), ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); self.mark_dirty(); self.overlay.clear_child_prefix(child_info, prefix); @@ -430,7 +472,7 @@ where HexDisplay::from(&value), ); - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); self.mark_dirty(); let backend = &mut self.backend; @@ -446,7 +488,7 @@ where } fn storage_root(&mut self) -> Vec { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); if let Some(ref root) = self.storage_transaction_cache.transaction_storage_root { trace!(target: "state", "{:04x}: Root(cached) {}", self.id, @@ -464,7 +506,7 @@ where &mut self, child_info: &ChildInfo, ) -> Vec { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let storage_key = child_info.storage_key(); let prefixed_storage_key = child_info.prefixed_storage_key(); if self.storage_transaction_cache.transaction_storage_root.is_some() { @@ -525,8 +567,14 @@ where } } + #[cfg(not(feature = "std"))] + fn storage_changes_root(&mut self, _parent_hash: &[u8]) -> Result>, ()> { + Ok(None) + } + + #[cfg(feature = "std")] fn storage_changes_root(&mut self, parent_hash: &[u8]) -> Result>, ()> { - let _guard = sp_panic_handler::AbortGuard::force_abort(); + let _guard = guard(); let root = self.overlay.changes_trie_root( self.backend, self.changes_trie_state.as_ref(), @@ -569,6 +617,7 @@ where } self.overlay.drain_storage_changes( &self.backend, + #[cfg(feature = "std")] None, Default::default(), self.storage_transaction_cache, @@ -586,6 +635,7 @@ where } let changes = self.overlay.drain_storage_changes( &self.backend, + #[cfg(feature = "std")] None, Default::default(), self.storage_transaction_cache, @@ -619,7 +669,6 @@ where } } - /// Implement `Encode` by forwarding the stored raw vec. struct EncodeOpaqueValue(Vec); @@ -644,12 +693,12 @@ impl<'a> StorageAppend<'a> { pub fn append(&mut self, value: Vec) { let value = vec![EncodeOpaqueValue(value)]; - let item = std::mem::take(self.0); + let item = sp_std::mem::take(self.0); *self.0 = match Vec::::append_or_new(item, &value) { Ok(item) => item, Err(_) => { - log::error!( + log_error!( target: "runtime", "Failed to append value, resetting storage item to `[value]`.", ); @@ -659,7 +708,36 @@ impl<'a> StorageAppend<'a> { } } -impl<'a, H, B, N> sp_externalities::ExtensionStore for Ext<'a, H, N, B> +#[cfg(not(feature = "std"))] +impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B> +where + H: Hasher, + H::Out: Ord + 'static + codec::Codec, + B: Backend, + N: crate::changes_trie::BlockNumber, +{ + fn extension_by_type_id(&mut self, _type_id: TypeId) -> Option<&mut dyn Any> { + None + } + + fn register_extension_with_type_id( + &mut self, + _type_id: TypeId, + _extension: Box, + ) -> Result<(), sp_externalities::Error> { + Err(sp_externalities::Error::ExtensionsAreNotSupported) + } + + fn deregister_extension_by_type_id( + &mut self, + _type_id: TypeId, + ) -> Result<(), sp_externalities::Error> { + Err(sp_externalities::Error::ExtensionsAreNotSupported) + } +} + +#[cfg(feature = "std")] +impl<'a, H, N, B> ExtensionStore for Ext<'a, H, N, B> where H: Hasher, B: 'a + Backend, diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index ee0980f59b926..5b86640aa7d0e 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -18,747 +18,851 @@ //! Substrate state machine implementation. #![warn(missing_docs)] - -use std::{fmt, result, collections::HashMap, panic::UnwindSafe}; -use log::{warn, trace}; -use hash_db::Hasher; -use codec::{Decode, Encode, Codec}; -use sp_core::{ - offchain::storage::OffchainOverlayedChanges, - storage::ChildInfo, NativeOrEncoded, NeverNativeValue, hexdisplay::HexDisplay, - traits::{CodeExecutor, CallInWasmExt, RuntimeCode, SpawnNamed}, -}; -use sp_externalities::Extensions; +#![cfg_attr(not(feature = "std"), no_std)] pub mod backend; +#[cfg(feature = "std")] mod in_memory_backend; +#[cfg(feature = "std")] mod changes_trie; mod error; mod ext; +#[cfg(feature = "std")] mod testing; +#[cfg(feature = "std")] mod basic; mod overlayed_changes; +#[cfg(feature = "std")] mod proving_backend; mod trie_backend; mod trie_backend_essence; mod stats; +#[cfg(feature = "std")] mod read_only; -pub use sp_trie::{trie_types::{Layout, TrieDBMut}, StorageProof, TrieMut, DBValue, MemoryDB}; -pub use testing::TestExternalities; -pub use basic::BasicExternalities; -pub use read_only::{ReadOnlyExternalities, InspectState}; -pub use ext::Ext; -pub use backend::Backend; -pub use changes_trie::{ - AnchorBlockId as ChangesTrieAnchorBlockId, - State as ChangesTrieState, - Storage as ChangesTrieStorage, - RootsStorage as ChangesTrieRootsStorage, - InMemoryStorage as InMemoryChangesTrieStorage, - BuildCache as ChangesTrieBuildCache, - CacheAction as ChangesTrieCacheAction, - ConfigurationRange as ChangesTrieConfigurationRange, - key_changes, key_changes_proof, - key_changes_proof_check, key_changes_proof_check_with_db, - prune as prune_changes_tries, - disabled_state as disabled_changes_trie_state, - BlockNumber as ChangesTrieBlockNumber, -}; -pub use overlayed_changes::{ - OverlayedChanges, StorageChanges, StorageTransactionCache, StorageKey, StorageValue, - StorageCollection, ChildStorageCollection, -}; -pub use proving_backend::{ - create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder, -}; -pub use trie_backend_essence::{TrieBackendStorage, Storage}; -pub use trie_backend::TrieBackend; -pub use error::{Error, ExecutionError}; -pub use in_memory_backend::new_in_mem; -pub use stats::{UsageInfo, UsageUnit, StateMachineStats}; - -const PROOF_CLOSE_TRANSACTION: &str = "\ - Closing a transaction that was started in this function. Client initiated transactions - are protected from being closed by the runtime. qed"; - -type CallResult = Result, E>; - -/// Default handler of the execution manager. -pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; - -/// Type of changes trie transaction. -pub type ChangesTrieTransaction = ( - MemoryDB, - 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 { - /// Execute with the native equivalent if it is compatible with the given wasm module; otherwise fall back to the wasm. - NativeWhenPossible, - /// Use the given wasm module. - AlwaysWasm, - /// Run with both the wasm and the native variant (if compatible). Report any discrepancy as an error. - Both, - /// First native, then if that fails or is not possible, wasm. - NativeElseWasm, +#[cfg(feature = "std")] +pub use std_reexport::*; + +#[cfg(feature = "std")] +pub use execution::*; +#[cfg(feature = "std")] +pub use log::{debug, warn, trace, error as log_error}; + +/// In no_std we skip logs for state_machine, this macro +/// is a noops. +#[cfg(not(feature = "std"))] +#[macro_export] +macro_rules! warn { + (target: $target:expr, $($arg:tt)+) => ( + () + ); + ($($arg:tt)+) => ( + () + ); } -/// Storage backend trust level. -#[derive(Debug, Clone)] -pub enum BackendTrustLevel { - /// Panics from trusted backends are considered justified, and never caught. - Trusted, - /// Panics from untrusted backend are caught and interpreted as runtime error. - /// Untrusted backend may be missing some parts of the trie, so panics are not considered - /// fatal. - Untrusted, +/// In no_std we skip logs for state_machine, this macro +/// is a noops. +#[cfg(not(feature = "std"))] +#[macro_export] +macro_rules! debug { + (target: $target:expr, $($arg:tt)+) => ( + () + ); + ($($arg:tt)+) => ( + () + ); } -/// Like `ExecutionStrategy` only it also stores a handler in case of consensus failure. -#[derive(Clone)] -pub enum ExecutionManager { - /// Execute with the native equivalent if it is compatible with the given wasm module; otherwise fall back to the wasm. - NativeWhenPossible, - /// Use the given wasm module. The backend on which code is executed code could be - /// trusted to provide all storage or not (i.e. the light client cannot be trusted to provide - /// for all storage queries since the storage entries it has come from an external node). - AlwaysWasm(BackendTrustLevel), - /// Run with both the wasm and the native variant (if compatible). Call `F` in the case of any discrepancy. - Both(F), - /// First native, then if that fails or is not possible, wasm. - NativeElseWasm, +/// In no_std we skip logs for state_machine, this macro +/// is a noops. +#[cfg(not(feature = "std"))] +#[macro_export] +macro_rules! trace { + (target: $target:expr, $($arg:tt)+) => ( + () + ); + ($($arg:tt)+) => ( + () + ); } -impl<'a, F> From<&'a ExecutionManager> for ExecutionStrategy { - fn from(s: &'a ExecutionManager) -> Self { - match *s { - ExecutionManager::NativeWhenPossible => ExecutionStrategy::NativeWhenPossible, - ExecutionManager::AlwaysWasm(_) => ExecutionStrategy::AlwaysWasm, - ExecutionManager::NativeElseWasm => ExecutionStrategy::NativeElseWasm, - ExecutionManager::Both(_) => ExecutionStrategy::Both, - } - } +/// In no_std we skip logs for state_machine, this macro +/// is a noops. +#[cfg(not(feature = "std"))] +#[macro_export] +macro_rules! log_error { + (target: $target:expr, $($arg:tt)+) => ( + () + ); + ($($arg:tt)+) => ( + () + ); } -impl ExecutionStrategy { - /// Gets the corresponding manager for the execution strategy. - pub fn get_manager( - self, - ) -> ExecutionManager> { - match self { - ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted), - ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible, - ExecutionStrategy::NativeElseWasm => ExecutionManager::NativeElseWasm, - ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| { - warn!( - "Consensus error between wasm {:?} and native {:?}. Using wasm.", - wasm_result, - native_result, - ); - warn!(" Native result {:?}", native_result); - warn!(" Wasm result {:?}", wasm_result); - wasm_result - }), - } +/// Default error type to use with state machine trie backend. +#[cfg(feature = "std")] +pub type DefaultError = String; +/// Error type to use with state machine trie backend. +#[cfg(not(feature = "std"))] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +pub struct DefaultError; + +#[cfg(not(feature = "std"))] +impl sp_std::fmt::Display for DefaultError { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "DefaultError") } } -/// Evaluate to ExecutionManager::NativeElseWasm, without having to figure out the type. -pub fn native_else_wasm() -> ExecutionManager> { - ExecutionManager::NativeElseWasm -} +pub use crate::overlayed_changes::{ + OverlayedChanges, StorageKey, StorageValue, + StorageCollection, ChildStorageCollection, + StorageChanges, StorageTransactionCache, +}; +pub use crate::backend::Backend; +pub use crate::trie_backend_essence::{TrieBackendStorage, Storage}; +pub use crate::trie_backend::TrieBackend; +pub use crate::stats::{UsageInfo, UsageUnit, StateMachineStats}; +pub use error::{Error, ExecutionError}; +pub use crate::ext::Ext; -/// Evaluate to ExecutionManager::AlwaysWasm with trusted backend, without having to figure out the type. -fn always_wasm() -> ExecutionManager> { - ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted) -} +#[cfg(not(feature = "std"))] +mod changes_trie { + /// Stub for change trie block number until + /// change trie move to no_std. + pub trait BlockNumber {} -/// Evaluate ExecutionManager::AlwaysWasm with untrusted backend, without having to figure out the type. -fn always_untrusted_wasm() -> ExecutionManager> { - ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted) + impl BlockNumber for N {} } -/// The substrate state machine. -pub struct StateMachine<'a, B, H, N, Exec> - where - H: Hasher, - B: Backend, - N: ChangesTrieBlockNumber, -{ - backend: &'a B, - exec: &'a Exec, - method: &'a str, - call_data: &'a [u8], - overlay: &'a mut OverlayedChanges, - offchain_overlay: &'a mut OffchainOverlayedChanges, - extensions: Extensions, - changes_trie_state: Option>, - storage_transaction_cache: Option<&'a mut StorageTransactionCache>, - runtime_code: &'a RuntimeCode<'a>, - stats: StateMachineStats, +#[cfg(feature = "std")] +mod std_reexport { + pub use sp_trie::{trie_types::{Layout, TrieDBMut}, StorageProof, TrieMut, DBValue, MemoryDB}; + pub use crate::testing::TestExternalities; + pub use crate::basic::BasicExternalities; + pub use crate::read_only::{ReadOnlyExternalities, InspectState}; + pub use crate::changes_trie::{ + AnchorBlockId as ChangesTrieAnchorBlockId, + State as ChangesTrieState, + Storage as ChangesTrieStorage, + RootsStorage as ChangesTrieRootsStorage, + InMemoryStorage as InMemoryChangesTrieStorage, + BuildCache as ChangesTrieBuildCache, + CacheAction as ChangesTrieCacheAction, + ConfigurationRange as ChangesTrieConfigurationRange, + key_changes, key_changes_proof, + key_changes_proof_check, key_changes_proof_check_with_db, + prune as prune_changes_tries, + disabled_state as disabled_changes_trie_state, + BlockNumber as ChangesTrieBlockNumber, + }; + pub use crate::proving_backend::{ + create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder, + }; + pub use crate::error::{Error, ExecutionError}; + pub use crate::in_memory_backend::new_in_mem; } -impl<'a, B, H, N, Exec> Drop for StateMachine<'a, B, H, N, Exec> where - H: Hasher, - B: Backend, - N: ChangesTrieBlockNumber, -{ - fn drop(&mut self) { - self.backend.register_overlay_stats(&self.stats); +#[cfg(feature = "std")] +mod execution { + use super::*; + use std::{fmt, result, collections::HashMap, panic::UnwindSafe}; + use log::{warn, trace}; + use hash_db::Hasher; + use codec::{Decode, Encode, Codec}; + use sp_core::{ + offchain::storage::OffchainOverlayedChanges, + storage::ChildInfo, NativeOrEncoded, NeverNativeValue, hexdisplay::HexDisplay, + traits::{CodeExecutor, CallInWasmExt, RuntimeCode, SpawnNamed}, + }; + use sp_externalities::Extensions; + + + const PROOF_CLOSE_TRANSACTION: &str = "\ + Closing a transaction that was started in this function. Client initiated transactions + are protected from being closed by the runtime. qed"; + + pub(crate) type CallResult = Result, E>; + + /// Default handler of the execution manager. + pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; + + /// Type of changes trie transaction. + pub type ChangesTrieTransaction = ( + MemoryDB, + 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 { + /// Execute with the native equivalent if it is compatible with the given wasm module; + /// otherwise fall back to the wasm. + NativeWhenPossible, + /// Use the given wasm module. + AlwaysWasm, + /// Run with both the wasm and the native variant (if compatible). Report any discrepancy as an error. + Both, + /// First native, then if that fails or is not possible, wasm. + NativeElseWasm, } -} -impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where - H: Hasher, - H::Out: Ord + 'static + codec::Codec, - Exec: CodeExecutor + Clone + 'static, - B: Backend, - N: crate::changes_trie::BlockNumber, -{ - /// Creates new substrate state machine. - pub fn new( - backend: &'a B, - changes_trie_state: Option>, - overlay: &'a mut OverlayedChanges, - offchain_overlay: &'a mut OffchainOverlayedChanges, - exec: &'a Exec, - method: &'a str, - call_data: &'a [u8], - mut extensions: Extensions, - runtime_code: &'a RuntimeCode, - spawn_handle: impl SpawnNamed + Send + 'static, - ) -> Self { - extensions.register(CallInWasmExt::new(exec.clone())); - extensions.register(sp_core::traits::TaskExecutorExt::new(spawn_handle)); - - Self { - backend, - exec, - method, - call_data, - extensions, - overlay, - offchain_overlay, - changes_trie_state, - storage_transaction_cache: None, - runtime_code, - stats: StateMachineStats::default(), - } + /// Storage backend trust level. + #[derive(Debug, Clone)] + pub enum BackendTrustLevel { + /// Panics from trusted backends are considered justified, and never caught. + Trusted, + /// Panics from untrusted backend are caught and interpreted as runtime error. + /// Untrusted backend may be missing some parts of the trie, so panics are not considered + /// fatal. + Untrusted, } - /// Use given `cache` as storage transaction cache. - /// - /// The cache will be used to cache storage transactions that can be build while executing a - /// function in the runtime. For example, when calculating the storage root a transaction is - /// build that will be cached. - pub fn with_storage_transaction_cache( - mut self, - cache: Option<&'a mut StorageTransactionCache>, - ) -> Self { - self.storage_transaction_cache = cache; - self + /// Like `ExecutionStrategy` only it also stores a handler in case of consensus failure. + #[derive(Clone)] + pub enum ExecutionManager { + /// Execute with the native equivalent if it is compatible with the given wasm module; + /// otherwise fall back to the wasm. + NativeWhenPossible, + /// Use the given wasm module. The backend on which code is executed code could be + /// trusted to provide all storage or not (i.e. the light client cannot be trusted to provide + /// for all storage queries since the storage entries it has come from an external node). + AlwaysWasm(BackendTrustLevel), + /// Run with both the wasm and the native variant (if compatible). Call `F` in the case of any discrepancy. + Both(F), + /// First native, then if that fails or is not possible, wasm. + NativeElseWasm, } - /// Execute a call using the given state backend, overlayed changes, and call executor. - /// - /// On an error, no prospective changes are written to the overlay. - /// - /// Note: changes to code will be in place if this call is made again. For running partial - /// blocks (e.g. a transaction at a time), ensure a different method is used. - /// - /// Returns the SCALE encoded result of the executed function. - pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result, Box> { - // We are not giving a native call and thus we are sure that the result can never be a native - // value. - self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - strategy.get_manager(), - None, - ).map(NativeOrEncoded::into_encoded) + impl<'a, F> From<&'a ExecutionManager> for ExecutionStrategy { + fn from(s: &'a ExecutionManager) -> Self { + match *s { + ExecutionManager::NativeWhenPossible => ExecutionStrategy::NativeWhenPossible, + ExecutionManager::AlwaysWasm(_) => ExecutionStrategy::AlwaysWasm, + ExecutionManager::NativeElseWasm => ExecutionStrategy::NativeElseWasm, + ExecutionManager::Both(_) => ExecutionStrategy::Both, + } + } } - fn execute_aux( - &mut self, - use_native: bool, - native_call: Option, - ) -> ( - CallResult, - bool, - ) where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - { - let mut cache = StorageTransactionCache::default(); + impl ExecutionStrategy { + /// Gets the corresponding manager for the execution strategy. + pub fn get_manager( + self, + ) -> ExecutionManager> { + match self { + ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted), + ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible, + ExecutionStrategy::NativeElseWasm => ExecutionManager::NativeElseWasm, + ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| { + warn!( + "Consensus error between wasm {:?} and native {:?}. Using wasm.", + wasm_result, + native_result, + ); + warn!(" Native result {:?}", native_result); + warn!(" Wasm result {:?}", wasm_result); + wasm_result + }), + } + } + } - let cache = match self.storage_transaction_cache.as_mut() { - Some(cache) => cache, - None => &mut cache, - }; + /// Evaluate to ExecutionManager::NativeElseWasm, without having to figure out the type. + pub fn native_else_wasm() -> ExecutionManager> { + ExecutionManager::NativeElseWasm + } - self.overlay.enter_runtime().expect("StateMachine is never called from the runtime; qed"); + /// Evaluate to ExecutionManager::AlwaysWasm with trusted backend, without having to figure out the type. + fn always_wasm() -> ExecutionManager> { + ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted) + } - let mut ext = Ext::new( - self.overlay, - self.offchain_overlay, - cache, - self.backend, - self.changes_trie_state.clone(), - Some(&mut self.extensions), - ); + /// Evaluate ExecutionManager::AlwaysWasm with untrusted backend, without having to figure out the type. + fn always_untrusted_wasm() -> ExecutionManager> { + ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted) + } - let id = ext.id; - trace!( - target: "state", "{:04x}: Call {} at {:?}. Input={:?}", - id, - self.method, - self.backend, - HexDisplay::from(&self.call_data), - ); + /// The substrate state machine. + pub struct StateMachine<'a, B, H, N, Exec> + where + H: Hasher, + B: Backend, + N: ChangesTrieBlockNumber, + { + backend: &'a B, + exec: &'a Exec, + method: &'a str, + call_data: &'a [u8], + overlay: &'a mut OverlayedChanges, + offchain_overlay: &'a mut OffchainOverlayedChanges, + extensions: Extensions, + changes_trie_state: Option>, + storage_transaction_cache: Option<&'a mut StorageTransactionCache>, + runtime_code: &'a RuntimeCode<'a>, + stats: StateMachineStats, + } - let (result, was_native) = self.exec.call( - &mut ext, - self.runtime_code, - self.method, - self.call_data, - use_native, - native_call, - ); + impl<'a, B, H, N, Exec> Drop for StateMachine<'a, B, H, N, Exec> where + H: Hasher, + B: Backend, + N: ChangesTrieBlockNumber, + { + fn drop(&mut self) { + self.backend.register_overlay_stats(&self.stats); + } + } - self.overlay.exit_runtime() - .expect("Runtime is not able to call this function in the overlay; qed"); + impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where + H: Hasher, + H::Out: Ord + 'static + codec::Codec, + Exec: CodeExecutor + Clone + 'static, + B: Backend, + N: crate::changes_trie::BlockNumber, + { + /// Creates new substrate state machine. + pub fn new( + backend: &'a B, + changes_trie_state: Option>, + overlay: &'a mut OverlayedChanges, + offchain_overlay: &'a mut OffchainOverlayedChanges, + exec: &'a Exec, + method: &'a str, + call_data: &'a [u8], + mut extensions: Extensions, + runtime_code: &'a RuntimeCode, + spawn_handle: impl SpawnNamed + Send + 'static, + ) -> Self { + extensions.register(CallInWasmExt::new(exec.clone())); + extensions.register(sp_core::traits::TaskExecutorExt::new(spawn_handle)); + + Self { + backend, + exec, + method, + call_data, + extensions, + overlay, + offchain_overlay, + changes_trie_state, + storage_transaction_cache: None, + runtime_code, + stats: StateMachineStats::default(), + } + } - trace!( - target: "state", "{:04x}: Return. Native={:?}, Result={:?}", - id, - was_native, - result, - ); + /// Use given `cache` as storage transaction cache. + /// + /// The cache will be used to cache storage transactions that can be build while executing a + /// function in the runtime. For example, when calculating the storage root a transaction is + /// build that will be cached. + pub fn with_storage_transaction_cache( + mut self, + cache: Option<&'a mut StorageTransactionCache>, + ) -> Self { + self.storage_transaction_cache = cache; + self + } - (result, was_native) - } + /// Execute a call using the given state backend, overlayed changes, and call executor. + /// + /// On an error, no prospective changes are written to the overlay. + /// + /// Note: changes to code will be in place if this call is made again. For running partial + /// blocks (e.g. a transaction at a time), ensure a different method is used. + /// + /// Returns the SCALE encoded result of the executed function. + pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result, Box> { + // We are not giving a native call and thus we are sure that the result can never be a native + // value. + self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( + strategy.get_manager(), + None, + ).map(NativeOrEncoded::into_encoded) + } - fn execute_call_with_both_strategy( - &mut self, - mut native_call: Option, - on_consensus_failure: Handler, - ) -> CallResult - where + fn execute_aux( + &mut self, + use_native: bool, + native_call: Option, + ) -> ( + CallResult, + bool, + ) where R: Decode + Encode + PartialEq, NC: FnOnce() -> result::Result + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult - { - self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux(true, native_call.take()); + { + let mut cache = StorageTransactionCache::default(); - if was_native { - self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux( - false, + let cache = match self.storage_transaction_cache.as_mut() { + Some(cache) => cache, + None => &mut cache, + }; + + self.overlay.enter_runtime().expect("StateMachine is never called from the runtime; qed"); + + let mut ext = Ext::new( + self.overlay, + self.offchain_overlay, + cache, + self.backend, + self.changes_trie_state.clone(), + Some(&mut self.extensions), + ); + + let id = ext.id; + trace!( + target: "state", "{:04x}: Call {} at {:?}. Input={:?}", + id, + self.method, + self.backend, + HexDisplay::from(&self.call_data), + ); + + let (result, was_native) = self.exec.call( + &mut ext, + self.runtime_code, + self.method, + self.call_data, + use_native, native_call, ); - if (result.is_ok() && wasm_result.is_ok() - && result.as_ref().ok() == wasm_result.as_ref().ok()) - || result.is_err() && wasm_result.is_err() - { + self.overlay.exit_runtime() + .expect("Runtime is not able to call this function in the overlay; qed"); + + trace!( + target: "state", "{:04x}: Return. Native={:?}, Result={:?}", + id, + was_native, + result, + ); + + (result, was_native) + } + + fn execute_call_with_both_strategy( + &mut self, + mut native_call: Option, + on_consensus_failure: Handler, + ) -> CallResult + where + R: Decode + Encode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, + Handler: FnOnce( + CallResult, + CallResult, + ) -> CallResult + { + self.overlay.start_transaction(); + let (result, was_native) = self.execute_aux(true, native_call.take()); + + if was_native { + self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); + let (wasm_result, _) = self.execute_aux( + false, + native_call, + ); + + if (result.is_ok() && wasm_result.is_ok() + && result.as_ref().ok() == wasm_result.as_ref().ok()) + || result.is_err() && wasm_result.is_err() + { + result + } else { + on_consensus_failure(wasm_result, result) + } + } else { + self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); + result + } + } + + fn execute_call_with_native_else_wasm_strategy( + &mut self, + mut native_call: Option, + ) -> CallResult + where + R: Decode + Encode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, + { + self.overlay.start_transaction(); + let (result, was_native) = self.execute_aux( + true, + native_call.take(), + ); + + if !was_native || result.is_ok() { + self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); result } else { - on_consensus_failure(wasm_result, result) + self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); + let (wasm_result, _) = self.execute_aux( + false, + native_call, + ); + wasm_result } - } else { - self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); - result + } + + /// Execute a call using the given state backend, overlayed changes, and call executor. + /// + /// On an error, no prospective changes are written to the overlay. + /// + /// Note: changes to code will be in place if this call is made again. For running partial + /// blocks (e.g. a transaction at a time), ensure a different method is used. + /// + /// Returns the result of the executed function either in native representation `R` or + /// in SCALE encoded representation. + pub fn execute_using_consensus_failure_handler( + &mut self, + manager: ExecutionManager, + mut native_call: Option, + ) -> Result, Box> + where + R: Decode + Encode + PartialEq, + NC: FnOnce() -> result::Result + UnwindSafe, + Handler: FnOnce( + CallResult, + CallResult, + ) -> CallResult + { + let changes_tries_enabled = self.changes_trie_state.is_some(); + self.overlay.set_collect_extrinsics(changes_tries_enabled); + + let result = { + match manager { + ExecutionManager::Both(on_consensus_failure) => { + self.execute_call_with_both_strategy( + native_call.take(), + on_consensus_failure, + ) + }, + ExecutionManager::NativeElseWasm => { + self.execute_call_with_native_else_wasm_strategy( + native_call.take(), + ) + }, + ExecutionManager::AlwaysWasm(trust_level) => { + let _abort_guard = match trust_level { + BackendTrustLevel::Trusted => None, + BackendTrustLevel::Untrusted => Some(sp_panic_handler::AbortGuard::never_abort()), + }; + self.execute_aux(false, native_call).0 + }, + ExecutionManager::NativeWhenPossible => { + self.execute_aux(true, native_call).0 + }, + } + }; + + result.map_err(|e| Box::new(e) as _) } } - fn execute_call_with_native_else_wasm_strategy( - &mut self, - mut native_call: Option, - ) -> CallResult - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, + /// Prove execution using the given state backend, overlayed changes, and call executor. + pub fn prove_execution( + mut backend: B, + overlay: &mut OverlayedChanges, + exec: &Exec, + spawn_handle: Spawn, + method: &str, + call_data: &[u8], + runtime_code: &RuntimeCode, + ) -> Result<(Vec, StorageProof), Box> + where + B: Backend, + H: Hasher, + H::Out: Ord + 'static + codec::Codec, + Exec: CodeExecutor + Clone + 'static, + N: crate::changes_trie::BlockNumber, + Spawn: SpawnNamed + Send + 'static, { - self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux( - true, - native_call.take(), - ); - - if !was_native || result.is_ok() { - self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); - result - } else { - self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux( - false, - native_call, - ); - wasm_result - } + let trie_backend = backend.as_trie_backend() + .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + prove_execution_on_trie_backend::<_, _, N, _, _>( + trie_backend, + overlay, + exec, + spawn_handle, + method, + call_data, + runtime_code, + ) } - /// Execute a call using the given state backend, overlayed changes, and call executor. + /// Prove execution using the given trie backend, overlayed changes, and call executor. + /// Produces a state-backend-specific "transaction" which can be used to apply the changes + /// to the backing store, such as the disk. + /// Execution proof is the set of all 'touched' storage DBValues from the backend. /// /// On an error, no prospective changes are written to the overlay. /// /// Note: changes to code will be in place if this call is made again. For running partial /// blocks (e.g. a transaction at a time), ensure a different method is used. - /// - /// Returns the result of the executed function either in native representation `R` or - /// in SCALE encoded representation. - pub fn execute_using_consensus_failure_handler( - &mut self, - manager: ExecutionManager, - mut native_call: Option, - ) -> Result, Box> - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult + pub fn prove_execution_on_trie_backend( + trie_backend: &TrieBackend, + overlay: &mut OverlayedChanges, + exec: &Exec, + spawn_handle: Spawn, + method: &str, + call_data: &[u8], + runtime_code: &RuntimeCode, + ) -> Result<(Vec, StorageProof), Box> + where + S: trie_backend_essence::TrieBackendStorage, + H: Hasher, + H::Out: Ord + 'static + codec::Codec, + Exec: CodeExecutor + 'static + Clone, + N: crate::changes_trie::BlockNumber, + Spawn: SpawnNamed + Send + 'static, { - let changes_tries_enabled = self.changes_trie_state.is_some(); - self.overlay.set_collect_extrinsics(changes_tries_enabled); - - let result = { - match manager { - ExecutionManager::Both(on_consensus_failure) => { - self.execute_call_with_both_strategy( - native_call.take(), - on_consensus_failure, - ) - }, - ExecutionManager::NativeElseWasm => { - self.execute_call_with_native_else_wasm_strategy( - native_call.take(), - ) - }, - ExecutionManager::AlwaysWasm(trust_level) => { - let _abort_guard = match trust_level { - BackendTrustLevel::Trusted => None, - BackendTrustLevel::Untrusted => Some(sp_panic_handler::AbortGuard::never_abort()), - }; - self.execute_aux(false, native_call).0 - }, - ExecutionManager::NativeWhenPossible => { - self.execute_aux(true, native_call).0 - }, - } - }; + let mut offchain_overlay = OffchainOverlayedChanges::default(); + let proving_backend = proving_backend::ProvingBackend::new(trie_backend); + let mut sm = StateMachine::<_, H, N, Exec>::new( + &proving_backend, + None, + overlay, + &mut offchain_overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, + spawn_handle, + ); - result.map_err(|e| Box::new(e) as _) + let result = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( + always_wasm(), + None, + )?; + let proof = sm.backend.extract_proof(); + Ok((result.into_encoded(), proof)) } -} -/// Prove execution using the given state backend, overlayed changes, and call executor. -pub fn prove_execution( - mut backend: B, - overlay: &mut OverlayedChanges, - exec: &Exec, - spawn_handle: Spawn, - method: &str, - call_data: &[u8], - runtime_code: &RuntimeCode, -) -> Result<(Vec, StorageProof), Box> -where - B: Backend, - H: Hasher, - H::Out: Ord + 'static + codec::Codec, - Exec: CodeExecutor + Clone + 'static, - N: crate::changes_trie::BlockNumber, - Spawn: SpawnNamed + Send + 'static, -{ - let trie_backend = backend.as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; - prove_execution_on_trie_backend::<_, _, N, _, _>( - trie_backend, - overlay, - exec, - spawn_handle, - method, - call_data, - runtime_code, - ) -} - -/// Prove execution using the given trie backend, overlayed changes, and call executor. -/// Produces a state-backend-specific "transaction" which can be used to apply the changes -/// to the backing store, such as the disk. -/// Execution proof is the set of all 'touched' storage DBValues from the backend. -/// -/// On an error, no prospective changes are written to the overlay. -/// -/// Note: changes to code will be in place if this call is made again. For running partial -/// blocks (e.g. a transaction at a time), ensure a different method is used. -pub fn prove_execution_on_trie_backend( - trie_backend: &TrieBackend, - overlay: &mut OverlayedChanges, - exec: &Exec, - spawn_handle: Spawn, - method: &str, - call_data: &[u8], - runtime_code: &RuntimeCode, -) -> Result<(Vec, StorageProof), Box> -where - S: trie_backend_essence::TrieBackendStorage, - H: Hasher, - H::Out: Ord + 'static + codec::Codec, - Exec: CodeExecutor + 'static + Clone, - N: crate::changes_trie::BlockNumber, - Spawn: SpawnNamed + Send + 'static, -{ - let mut offchain_overlay = OffchainOverlayedChanges::default(); - let proving_backend = proving_backend::ProvingBackend::new(trie_backend); - let mut sm = StateMachine::<_, H, N, Exec>::new( - &proving_backend, - None, - overlay, - &mut offchain_overlay, - exec, - method, - call_data, - Extensions::default(), - runtime_code, - spawn_handle, - ); - - let result = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_wasm(), - None, - )?; - let proof = sm.backend.extract_proof(); - Ok((result.into_encoded(), proof)) -} - -/// Check execution proof, generated by `prove_execution` call. -pub fn execution_proof_check( - root: H::Out, - proof: StorageProof, - overlay: &mut OverlayedChanges, - exec: &Exec, - spawn_handle: Spawn, - method: &str, - call_data: &[u8], - runtime_code: &RuntimeCode, -) -> Result, Box> -where - H: Hasher, - Exec: CodeExecutor + Clone + 'static, - H::Out: Ord + 'static + codec::Codec, - N: crate::changes_trie::BlockNumber, - Spawn: SpawnNamed + Send + 'static, -{ - let trie_backend = create_proof_check_backend::(root.into(), proof)?; - execution_proof_check_on_trie_backend::<_, N, _, _>( - &trie_backend, - overlay, - exec, - spawn_handle, - method, - call_data, - runtime_code, - ) -} + /// Check execution proof, generated by `prove_execution` call. + pub fn execution_proof_check( + root: H::Out, + proof: StorageProof, + overlay: &mut OverlayedChanges, + exec: &Exec, + spawn_handle: Spawn, + method: &str, + call_data: &[u8], + runtime_code: &RuntimeCode, + ) -> Result, Box> + where + H: Hasher, + Exec: CodeExecutor + Clone + 'static, + H::Out: Ord + 'static + codec::Codec, + N: crate::changes_trie::BlockNumber, + Spawn: SpawnNamed + Send + 'static, + { + let trie_backend = create_proof_check_backend::(root.into(), proof)?; + execution_proof_check_on_trie_backend::<_, N, _, _>( + &trie_backend, + overlay, + exec, + spawn_handle, + method, + call_data, + runtime_code, + ) + } -/// Check execution proof on proving backend, generated by `prove_execution` call. -pub fn execution_proof_check_on_trie_backend( - trie_backend: &TrieBackend, H>, - overlay: &mut OverlayedChanges, - exec: &Exec, - spawn_handle: Spawn, - method: &str, - call_data: &[u8], - runtime_code: &RuntimeCode, -) -> Result, Box> -where - H: Hasher, - H::Out: Ord + 'static + codec::Codec, - Exec: CodeExecutor + Clone + 'static, - N: crate::changes_trie::BlockNumber, - Spawn: SpawnNamed + Send + 'static, -{ - let mut offchain_overlay = OffchainOverlayedChanges::default(); - let mut sm = StateMachine::<_, H, N, Exec>::new( - trie_backend, - None, - overlay, - &mut offchain_overlay, - exec, - method, - call_data, - Extensions::default(), - runtime_code, - spawn_handle, - ); + /// Check execution proof on proving backend, generated by `prove_execution` call. + pub fn execution_proof_check_on_trie_backend( + trie_backend: &TrieBackend, H>, + overlay: &mut OverlayedChanges, + exec: &Exec, + spawn_handle: Spawn, + method: &str, + call_data: &[u8], + runtime_code: &RuntimeCode, + ) -> Result, Box> + where + H: Hasher, + H::Out: Ord + 'static + codec::Codec, + Exec: CodeExecutor + Clone + 'static, + N: crate::changes_trie::BlockNumber, + Spawn: SpawnNamed + Send + 'static, + { + let mut offchain_overlay = OffchainOverlayedChanges::default(); + let mut sm = StateMachine::<_, H, N, Exec>::new( + trie_backend, + None, + overlay, + &mut offchain_overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, + spawn_handle, + ); - sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_untrusted_wasm(), - None, - ).map(NativeOrEncoded::into_encoded) -} + sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( + always_untrusted_wasm(), + None, + ).map(NativeOrEncoded::into_encoded) + } -/// Generate storage read proof. -pub fn prove_read( - mut backend: B, - keys: I, -) -> Result> -where - B: Backend, - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let trie_backend = backend.as_trie_backend() - .ok_or_else( - || Box::new(ExecutionError::UnableToGenerateProof) as Box - )?; - prove_read_on_trie_backend(trie_backend, keys) -} + /// Generate storage read proof. + pub fn prove_read( + mut backend: B, + keys: I, + ) -> Result> + where + B: Backend, + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let trie_backend = backend.as_trie_backend() + .ok_or_else( + || Box::new(ExecutionError::UnableToGenerateProof) as Box + )?; + prove_read_on_trie_backend(trie_backend, keys) + } -/// Generate child storage read proof. -pub fn prove_child_read( - mut backend: B, - child_info: &ChildInfo, - keys: I, -) -> Result> -where - B: Backend, - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let trie_backend = backend.as_trie_backend() - .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; - prove_child_read_on_trie_backend(trie_backend, child_info, keys) -} + /// Generate child storage read proof. + pub fn prove_child_read( + mut backend: B, + child_info: &ChildInfo, + keys: I, + ) -> Result> + where + B: Backend, + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let trie_backend = backend.as_trie_backend() + .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; + prove_child_read_on_trie_backend(trie_backend, child_info, keys) + } -/// Generate storage read proof on pre-created trie backend. -pub fn prove_read_on_trie_backend( - trie_backend: &TrieBackend, - keys: I, -) -> Result> -where - S: trie_backend_essence::TrieBackendStorage, - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); - for key in keys.into_iter() { - proving_backend - .storage(key.as_ref()) - .map_err(|e| Box::new(e) as Box)?; + /// Generate storage read proof on pre-created trie backend. + pub fn prove_read_on_trie_backend( + trie_backend: &TrieBackend, + keys: I, + ) -> Result> + where + S: trie_backend_essence::TrieBackendStorage, + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); + for key in keys.into_iter() { + proving_backend + .storage(key.as_ref()) + .map_err(|e| Box::new(e) as Box)?; + } + Ok(proving_backend.extract_proof()) } - Ok(proving_backend.extract_proof()) -} -/// Generate storage read proof on pre-created trie backend. -pub fn prove_child_read_on_trie_backend( - trie_backend: &TrieBackend, - child_info: &ChildInfo, - keys: I, -) -> Result> -where - S: trie_backend_essence::TrieBackendStorage, - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); - for key in keys.into_iter() { - proving_backend - .child_storage(child_info, key.as_ref()) - .map_err(|e| Box::new(e) as Box)?; + /// Generate storage read proof on pre-created trie backend. + pub fn prove_child_read_on_trie_backend( + trie_backend: &TrieBackend, + child_info: &ChildInfo, + keys: I, + ) -> Result> + where + S: trie_backend_essence::TrieBackendStorage, + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend); + for key in keys.into_iter() { + proving_backend + .child_storage(child_info, key.as_ref()) + .map_err(|e| Box::new(e) as Box)?; + } + Ok(proving_backend.extract_proof()) } - Ok(proving_backend.extract_proof()) -} -/// Check storage read proof, generated by `prove_read` call. -pub fn read_proof_check( - root: H::Out, - proof: StorageProof, - keys: I, -) -> Result, Option>>, Box> -where - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let proving_backend = create_proof_check_backend::(root, proof)?; - let mut result = HashMap::new(); - for key in keys.into_iter() { - let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; - result.insert(key.as_ref().to_vec(), value); + /// Check storage read proof, generated by `prove_read` call. + pub fn read_proof_check( + root: H::Out, + proof: StorageProof, + keys: I, + ) -> Result, Option>>, Box> + where + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = create_proof_check_backend::(root, proof)?; + let mut result = HashMap::new(); + for key in keys.into_iter() { + let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?; + result.insert(key.as_ref().to_vec(), value); + } + Ok(result) } - Ok(result) -} -/// Check child storage read proof, generated by `prove_child_read` call. -pub fn read_child_proof_check( - root: H::Out, - proof: StorageProof, - child_info: &ChildInfo, - keys: I, -) -> Result, Option>>, Box> -where - H: Hasher, - H::Out: Ord + Codec, - I: IntoIterator, - I::Item: AsRef<[u8]>, -{ - let proving_backend = create_proof_check_backend::(root, proof)?; - let mut result = HashMap::new(); - for key in keys.into_iter() { - let value = read_child_proof_check_on_proving_backend( - &proving_backend, - child_info, - key.as_ref(), - )?; - result.insert(key.as_ref().to_vec(), value); + /// Check child storage read proof, generated by `prove_child_read` call. + pub fn read_child_proof_check( + root: H::Out, + proof: StorageProof, + child_info: &ChildInfo, + keys: I, + ) -> Result, Option>>, Box> + where + H: Hasher, + H::Out: Ord + Codec, + I: IntoIterator, + I::Item: AsRef<[u8]>, + { + let proving_backend = create_proof_check_backend::(root, proof)?; + let mut result = HashMap::new(); + for key in keys.into_iter() { + let value = read_child_proof_check_on_proving_backend( + &proving_backend, + child_info, + key.as_ref(), + )?; + result.insert(key.as_ref().to_vec(), value); + } + Ok(result) } - Ok(result) -} -/// Check storage read proof on pre-created proving backend. -pub fn read_proof_check_on_proving_backend( - proving_backend: &TrieBackend, H>, - key: &[u8], -) -> Result>, Box> -where - H: Hasher, - H::Out: Ord + Codec, -{ - proving_backend.storage(key).map_err(|e| Box::new(e) as Box) -} + /// Check storage read proof on pre-created proving backend. + pub fn read_proof_check_on_proving_backend( + proving_backend: &TrieBackend, H>, + key: &[u8], + ) -> Result>, Box> + where + H: Hasher, + H::Out: Ord + Codec, + { + proving_backend.storage(key).map_err(|e| Box::new(e) as Box) + } -/// Check child storage read proof on pre-created proving backend. -pub fn read_child_proof_check_on_proving_backend( - proving_backend: &TrieBackend, H>, - child_info: &ChildInfo, - key: &[u8], -) -> Result>, Box> -where - H: Hasher, - H::Out: Ord + Codec, -{ - proving_backend.child_storage(child_info, key) - .map_err(|e| Box::new(e) as Box) + /// Check child storage read proof on pre-created proving backend. + pub fn read_child_proof_check_on_proving_backend( + proving_backend: &TrieBackend, H>, + child_info: &ChildInfo, + key: &[u8], + ) -> Result>, Box> + where + H: Hasher, + H::Out: Ord + Codec, + { + proving_backend.child_storage(child_info, key) + .map_err(|e| Box::new(e) as Box) + } } #[cfg(test)] @@ -772,6 +876,15 @@ mod tests { map, traits::{Externalities, RuntimeCode}, testing::TaskExecutor, }; use sp_runtime::traits::BlakeTwo256; + use std::{result, collections::HashMap}; + use codec::Decode; + use sp_core::{ + offchain::storage::OffchainOverlayedChanges, + storage::ChildInfo, NativeOrEncoded, NeverNativeValue, + traits::CodeExecutor, + }; + use crate::execution::CallResult; + #[derive(Clone)] struct DummyCodeExecutor { diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index fe43c0ea99d89..5e4fd77c68563 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -17,18 +17,22 @@ //! Houses the code that implements the transactional overlay storage. -use super::{StorageKey, StorageValue}; +use super::{StorageKey, StorageValue, Extrinsics}; -use itertools::Itertools; -use std::collections::{HashSet, BTreeMap, BTreeSet}; +#[cfg(feature = "std")] +use std::collections::HashSet as Set; +#[cfg(not(feature = "std"))] +use sp_std::collections::btree_set::BTreeSet as Set; + +use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use smallvec::SmallVec; -use log::warn; +use crate::warn; const PROOF_OVERLAY_NON_EMPTY: &str = "\ An OverlayValue is always created with at least one transaction and dropped as soon as the last transaction is removed; qed"; -type DirtyKeysSets = SmallVec<[HashSet; 5]>; +type DirtyKeysSets = SmallVec<[Set; 5]>; type Transactions = SmallVec<[InnerValue; 5]>; /// Error returned when trying to commit or rollback while no transaction is open or @@ -63,7 +67,7 @@ struct InnerValue { value: Option, /// The set of extrinsic indices where the values has been changed. /// Is filled only if runtime has announced changes trie support. - extrinsics: BTreeSet, + extrinsics: Extrinsics, } /// An overlay that contains all versions of a value for a specific key. @@ -105,8 +109,10 @@ impl OverlayedValue { } /// Unique list of extrinsic indices which modified the value. - pub fn extrinsics(&self) -> impl Iterator { - self.transactions.iter().flat_map(|t| t.extrinsics.iter()).unique() + pub fn extrinsics(&self) -> BTreeSet { + let mut set = BTreeSet::new(); + self.transactions.iter().for_each(|t| t.extrinsics.copy_extrinsics_into(&mut set)); + set } /// Mutable reference to the most recent version. @@ -120,7 +126,7 @@ impl OverlayedValue { } /// Mutable reference to the set which holds the indices for the **current transaction only**. - fn transaction_extrinsics_mut(&mut self) -> &mut BTreeSet { + fn transaction_extrinsics_mut(&mut self) -> &mut Extrinsics { &mut self.transactions.last_mut().expect(PROOF_OVERLAY_NON_EMPTY).extrinsics } @@ -163,9 +169,9 @@ impl OverlayedChangeSet { /// This changeset might be created when there are already open transactions. /// We need to catch up here so that the child is at the same transaction depth. pub fn spawn_child(&self) -> Self { - use std::iter::repeat; + use sp_std::iter::repeat; Self { - dirty_keys: repeat(HashSet::new()).take(self.transaction_depth()).collect(), + dirty_keys: repeat(Set::new()).take(self.transaction_depth()).collect(), num_client_transactions: self.num_client_transactions, execution_mode: self.execution_mode, .. Default::default() @@ -232,7 +238,7 @@ impl OverlayedChangeSet { at_extrinsic: Option, ) { for (key, val) in self.changes.iter_mut().filter(|(k, v)| predicate(k, v)) { - val.set(None, insert_dirty(&mut self.dirty_keys, key.to_owned()), at_extrinsic); + val.set(None, insert_dirty(&mut self.dirty_keys, key.clone()), at_extrinsic); } } @@ -243,7 +249,7 @@ impl OverlayedChangeSet { /// Get the change that is next to the supplied key. pub fn next_change(&self, key: &[u8]) -> Option<(&[u8], &OverlayedValue)> { - use std::ops::Bound; + use sp_std::ops::Bound; let range = (Bound::Excluded(key), Bound::Unbounded); self.changes.range::<[u8], _>(range).next().map(|(k, v)| (&k[..], v)) } @@ -388,7 +394,7 @@ mod test { fn assert_changes(is: &OverlayedChangeSet, expected: &Changes) { let is: Changes = is.changes().map(|(k, v)| { - (k.as_ref(), (v.value().map(AsRef::as_ref), v.extrinsics().cloned().collect())) + (k.as_ref(), (v.value().map(AsRef::as_ref), v.extrinsics().into_iter().collect())) }).collect(); assert_eq!(&is, expected); } diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 9a2b1c4197310..992f7b3519299 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -20,23 +20,38 @@ mod changeset; use crate::{ - backend::Backend, ChangesTrieTransaction, - changes_trie::{ - NO_EXTRINSIC_INDEX, BlockNumber, build_changes_trie, - State as ChangesTrieState, - }, + backend::Backend, stats::StateMachineStats, }; +use sp_std::vec::Vec; use self::changeset::OverlayedChangeSet; -use std::collections::HashMap; +#[cfg(feature = "std")] +use crate::{ + ChangesTrieTransaction, + changes_trie::{ + build_changes_trie, + State as ChangesTrieState, + }, +}; +use crate::changes_trie::BlockNumber; +#[cfg(feature = "std")] +use std::collections::HashMap as Map; +#[cfg(not(feature = "std"))] +use sp_std::collections::btree_map::BTreeMap as Map; +use sp_std::collections::btree_set::BTreeSet; use codec::{Decode, Encode}; use sp_core::storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo}; +#[cfg(feature = "std")] use sp_core::offchain::storage::OffchainOverlayedChanges; use hash_db::Hasher; +use crate::DefaultError; pub use self::changeset::{OverlayedValue, NoOpenTransaction, AlreadyInRuntime, NotInRuntime}; +/// Changes that are made outside of extrinsics are marked with this index; +pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff; + /// Storage key. pub type StorageKey = Vec; @@ -49,6 +64,29 @@ pub type StorageCollection = Vec<(StorageKey, Option)>; /// In memory arrays of storage values for multiple child tries. pub type ChildStorageCollection = Vec<(StorageKey, StorageCollection)>; +/// Keep trace of extrinsics index for a modified value. +#[derive(Debug, Default, Eq, PartialEq, Clone)] +pub struct Extrinsics(Vec); + +impl Extrinsics { + /// Extracts extrinsics into a `BTreeSets`. + fn copy_extrinsics_into(&self, dest: &mut BTreeSet) { + dest.extend(self.0.iter()) + } + + /// Add an extrinsics. + fn insert(&mut self, ext: u32) { + if Some(&ext) != self.0.last() { + self.0.push(ext); + } + } + + /// Extend `self` with `other`. + fn extend(&mut self, other: Self) { + self.0.extend(other.0.into_iter()); + } +} + /// The set of changes that are overlaid onto the backend. /// /// It allows changes to be modified using nestable transactions. @@ -57,7 +95,7 @@ pub struct OverlayedChanges { /// Top level storage changes. top: OverlayedChangeSet, /// Child storage changes. The map key is the child storage key without the common prefix. - children: HashMap, + children: Map, /// True if extrinsics stats must be collected. collect_extrinsics: bool, /// Collect statistic on this execution. @@ -76,6 +114,7 @@ pub struct StorageChanges { /// All changes to the child storages. pub child_storage_changes: ChildStorageCollection, /// Offchain state changes to write to the offchain database. + #[cfg(feature = "std")] pub offchain_storage_changes: OffchainOverlayedChanges, /// A transaction for the backend that contains all changes from /// [`main_storage_changes`](StorageChanges::main_storage_changes) and from @@ -87,9 +126,14 @@ pub struct StorageChanges { /// Contains the transaction for the backend for the changes trie. /// /// If changes trie is disabled the value is set to `None`. + #[cfg(feature = "std")] pub changes_trie_transaction: Option>, + /// Phantom data for block number until change trie support no_std. + #[cfg(not(feature = "std"))] + pub _ph: sp_std::marker::PhantomData, } +#[cfg(feature = "std")] impl StorageChanges { /// Deconstruct into the inner values pub fn into_inner(self) -> ( @@ -120,9 +164,14 @@ pub struct StorageTransactionCache { /// The storage root after applying the transaction. pub(crate) transaction_storage_root: Option, /// Contains the changes trie transaction. + #[cfg(feature = "std")] pub(crate) changes_trie_transaction: Option>>, /// The storage root after applying the changes trie transaction. + #[cfg(feature = "std")] pub(crate) changes_trie_transaction_storage_root: Option>, + /// Phantom data for block number until change trie support no_std. + #[cfg(not(feature = "std"))] + pub(crate) _ph: sp_std::marker::PhantomData, } impl StorageTransactionCache { @@ -137,8 +186,12 @@ impl Default for StorageTransactionCache Self { transaction: None, transaction_storage_root: None, + #[cfg(feature = "std")] changes_trie_transaction: None, + #[cfg(feature = "std")] changes_trie_transaction_storage_root: None, + #[cfg(not(feature = "std"))] + _ph: Default::default(), } } } @@ -148,10 +201,14 @@ impl Default for StorageChanges Self { main_storage_changes: Default::default(), child_storage_changes: Default::default(), + #[cfg(feature = "std")] offchain_storage_changes: Default::default(), transaction: Default::default(), transaction_storage_root: Default::default(), + #[cfg(feature = "std")] changes_trie_transaction: None, + #[cfg(not(feature = "std"))] + _ph: Default::default(), } } } @@ -190,7 +247,7 @@ impl OverlayedChanges { key: &[u8], init: impl Fn() -> StorageValue, ) -> &mut StorageValue { - let value = self.top.modify(key.to_owned(), init, self.extrinsic_index()); + let value = self.top.modify(key.to_vec(), init, self.extrinsic_index()); // if the value was deleted initialise it back with an empty vec value.get_or_insert_with(StorageValue::default) @@ -235,7 +292,7 @@ impl OverlayedChanges { let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| ( top.spawn_child(), - child_info.to_owned() + child_info.clone() ) ); let updatable = info.try_update(child_info); @@ -256,7 +313,7 @@ impl OverlayedChanges { let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| ( top.spawn_child(), - child_info.to_owned() + child_info.clone() ) ); let updatable = info.try_update(child_info); @@ -285,7 +342,7 @@ impl OverlayedChanges { let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| ( top.spawn_child(), - child_info.to_owned() + child_info.clone() ) ); let updatable = info.try_update(child_info); @@ -322,7 +379,7 @@ impl OverlayedChanges { /// there is no open transaction that can be rolled back. pub fn rollback_transaction(&mut self) -> Result<(), NoOpenTransaction> { self.top.rollback_transaction()?; - self.children.retain(|_, (changeset, _)| { + retain_map(&mut self.children, |_, (changeset, _)| { changeset.rollback_transaction() .expect("Top and children changesets are started in lockstep; qed"); !changeset.is_empty() @@ -379,7 +436,7 @@ impl OverlayedChanges { impl Iterator)>, impl Iterator)>, ChildInfo))>, ) { - use std::mem::take; + use sp_std::mem::take; ( take(&mut self.top).drain_commited(), take(&mut self.children).into_iter() @@ -409,6 +466,7 @@ impl OverlayedChanges { } /// Convert this instance with all changes into a [`StorageChanges`] instance. + #[cfg(feature = "std")] pub fn into_storage_changes< B: Backend, H: Hasher, N: BlockNumber >( @@ -417,7 +475,8 @@ impl OverlayedChanges { changes_trie_state: Option<&ChangesTrieState>, parent_hash: H::Out, mut cache: StorageTransactionCache, - ) -> Result, String> where H::Out: Ord + Encode + 'static { + ) -> Result, DefaultError> + where H::Out: Ord + Encode + 'static { self.drain_storage_changes(backend, changes_trie_state, parent_hash, &mut cache) } @@ -425,10 +484,12 @@ impl OverlayedChanges { pub fn drain_storage_changes, H: Hasher, N: BlockNumber>( &mut self, backend: &B, + #[cfg(feature = "std")] changes_trie_state: Option<&ChangesTrieState>, parent_hash: H::Out, mut cache: &mut StorageTransactionCache, - ) -> Result, String> where H::Out: Ord + Encode + 'static { + ) -> Result, DefaultError> + where H::Out: Ord + Encode + 'static { // If the transaction does not exist, we generate it. if cache.transaction.is_none() { self.storage_root(backend, &mut cache); @@ -439,6 +500,7 @@ impl OverlayedChanges { .expect("Transaction was be generated as part of `storage_root`; qed"); // If the transaction does not exist, we generate it. + #[cfg(feature = "std")] if cache.changes_trie_transaction.is_none() { self.changes_trie_root( backend, @@ -449,20 +511,24 @@ impl OverlayedChanges { ).map_err(|_| "Failed to generate changes trie transaction")?; } + #[cfg(feature = "std")] let changes_trie_transaction = cache.changes_trie_transaction .take() .expect("Changes trie transaction was generated by `changes_trie_root`; qed"); - let offchain_storage_changes = Default::default(); let (main_storage_changes, child_storage_changes) = self.drain_committed(); Ok(StorageChanges { main_storage_changes: main_storage_changes.collect(), child_storage_changes: child_storage_changes.map(|(sk, it)| (sk, it.0.collect())).collect(), - offchain_storage_changes, + #[cfg(feature = "std")] + offchain_storage_changes: Default::default(), transaction, transaction_storage_root, + #[cfg(feature = "std")] changes_trie_transaction, + #[cfg(not(feature = "std"))] + _ph: Default::default(), }) } @@ -520,6 +586,7 @@ impl OverlayedChanges { /// # Panics /// /// Panics on storage error, when `panic_on_storage_error` is set. + #[cfg(feature = "std")] pub fn changes_trie_root<'a, H: Hasher, N: BlockNumber, B: Backend>( &self, backend: &B, @@ -563,6 +630,29 @@ impl OverlayedChanges { } } +#[cfg(feature = "std")] +fn retain_map(map: &mut Map, f: F) + where + K: std::cmp::Eq + std::hash::Hash, + F: FnMut(&K, &mut V) -> bool, +{ + map.retain(f); +} + +#[cfg(not(feature = "std"))] +fn retain_map(map: &mut Map, mut f: F) + where + K: Ord, + F: FnMut(&K, &mut V) -> bool, +{ + let old = sp_std::mem::replace(map, Map::default()); + for (k, mut v) in old.into_iter() { + if f(&k, &mut v) { + map.insert(k, v); + } + } +} + #[cfg(test)] mod tests { use hex_literal::hex; @@ -578,7 +668,7 @@ mod tests { expected: Vec, ) { assert_eq!( - overlay.get(key.as_ref()).unwrap().extrinsics().cloned().collect::>(), + overlay.get(key.as_ref()).unwrap().extrinsics().into_iter().collect::>(), expected ) } diff --git a/primitives/state-machine/src/stats.rs b/primitives/state-machine/src/stats.rs index a8ca5a3b416f4..f84de6a5bad07 100644 --- a/primitives/state-machine/src/stats.rs +++ b/primitives/state-machine/src/stats.rs @@ -17,8 +17,9 @@ //! Usage statistics for state db +#[cfg(feature = "std")] use std::time::{Instant, Duration}; -use std::cell::RefCell; +use sp_std::cell::RefCell; /// Measured count of operations and total bytes. #[derive(Clone, Debug, Default)] @@ -50,8 +51,10 @@ pub struct UsageInfo { /// Memory used. pub memory: usize, + #[cfg(feature = "std")] /// Moment at which current statistics has been started being collected. pub started: Instant, + #[cfg(feature = "std")] /// Timespan of the statistics. pub span: Duration, } @@ -99,7 +102,9 @@ impl UsageInfo { cache_reads: UsageUnit::default(), modified_reads: UsageUnit::default(), memory: 0, + #[cfg(feature = "std")] started: Instant::now(), + #[cfg(feature = "std")] span: Default::default(), } } diff --git a/primitives/state-machine/src/trie_backend.rs b/primitives/state-machine/src/trie_backend.rs index e0a86bbd193a1..4eaa0870baed0 100644 --- a/primitives/state-machine/src/trie_backend.rs +++ b/primitives/state-machine/src/trie_backend.rs @@ -17,7 +17,7 @@ //! Trie-based state machine backend. -use log::{warn, debug}; +use crate::{warn, debug}; use hash_db::Hasher; use sp_trie::{Trie, delta_trie_root, empty_child_trie_root, child_delta_trie_root}; use sp_trie::trie_types::{TrieDB, TrieError, Layout}; @@ -27,6 +27,7 @@ use crate::{ StorageKey, StorageValue, Backend, trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral}, }; +use sp_std::{boxed::Box, vec::Vec}; /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher> { @@ -67,8 +68,8 @@ impl, H: Hasher> TrieBackend where H::Out: Codec } } -impl, H: Hasher> std::fmt::Debug for TrieBackend { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl, H: Hasher> sp_std::fmt::Debug for TrieBackend { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { write!(f, "TrieBackend") } } @@ -76,7 +77,7 @@ impl, H: Hasher> std::fmt::Debug for TrieBackend impl, H: Hasher> Backend for TrieBackend where H::Out: Ord + Codec, { - type Error = String; + type Error = crate::DefaultError; type Transaction = S::Overlay; type TrieBackendStorage = S; diff --git a/primitives/state-machine/src/trie_backend_essence.rs b/primitives/state-machine/src/trie_backend_essence.rs index 72864e312b6ab..37bbbb7cf9822 100644 --- a/primitives/state-machine/src/trie_backend_essence.rs +++ b/primitives/state-machine/src/trie_backend_essence.rs @@ -18,9 +18,10 @@ //! Trie-based state machine backend essence used to read values //! from storage. -use std::ops::Deref; +#[cfg(feature = "std")] use std::sync::Arc; -use log::{debug, warn}; +use sp_std::{ops::Deref, boxed::Box, vec::Vec}; +use crate::{warn, debug}; use hash_db::{self, Hasher, Prefix}; use sp_trie::{Trie, MemoryDB, PrefixedMemoryDB, DBValue, empty_child_trie_root, read_trie_value, read_child_trie_value, @@ -30,10 +31,19 @@ use crate::{backend::Consolidate, StorageKey, StorageValue}; use sp_core::storage::ChildInfo; use codec::Encode; +#[cfg(not(feature = "std"))] +macro_rules! format { + ($($arg:tt)+) => ( + crate::DefaultError + ); +} + +type Result = sp_std::result::Result; + /// Patricia trie-based storage trait. pub trait Storage: Send + Sync { /// Get a trie node. - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String>; + fn get(&self, key: &H::Out, prefix: Prefix) -> Result>; } /// Patricia trie-based pairs storage essence. @@ -80,12 +90,12 @@ impl, H: Hasher> TrieBackendEssence where H::Out: /// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in /// lexicographic order. - pub fn next_storage_key(&self, key: &[u8]) -> Result, String> { + pub fn next_storage_key(&self, key: &[u8]) -> Result> { self.next_storage_key_from_root(&self.root, None, key) } /// Access the root of the child storage in its parent trie - fn child_root(&self, child_info: &ChildInfo) -> Result, String> { + fn child_root(&self, child_info: &ChildInfo) -> Result> { self.storage(child_info.prefixed_storage_key().as_slice()) } @@ -95,7 +105,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: &self, child_info: &ChildInfo, key: &[u8], - ) -> Result, String> { + ) -> Result> { let child_root = match self.child_root(child_info)? { Some(child_root) => child_root, None => return Ok(None), @@ -118,7 +128,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: root: &H::Out, child_info: Option<&ChildInfo>, key: &[u8], - ) -> Result, String> { + ) -> Result> { let dyn_eph: &dyn hash_db::HashDBRef<_, _>; let keyspace_eph; if let Some(child_info) = child_info.as_ref() { @@ -158,7 +168,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: } /// Get the value of storage at given key. - pub fn storage(&self, key: &[u8]) -> Result, String> { + pub fn storage(&self, key: &[u8]) -> Result> { let map_e = |e| format!("Trie lookup error: {}", e); read_trie_value::, _>(self, &self.root, key).map_err(map_e) @@ -169,7 +179,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: &self, child_info: &ChildInfo, key: &[u8], - ) -> Result, String> { + ) -> Result> { let root = self.child_root(child_info)? .unwrap_or_else(|| empty_child_trie_root::>().encode()); @@ -234,7 +244,7 @@ impl, H: Hasher> TrieBackendEssence where H::Out: mut f: F, child_info: Option<&ChildInfo>, ) { - let mut iter = move |db| -> Result<(), Box>> { + let mut iter = move |db| -> sp_std::result::Result<(), Box>> { let trie = TrieDB::::new(db, root)?; for x in TrieDBIterator::new_prefixed(&trie, prefix)? { @@ -337,14 +347,15 @@ pub trait TrieBackendStorage: Send + Sync { /// Type of in-memory overlay. type Overlay: hash_db::HashDB + Default + Consolidate; /// Get the value stored at key. - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String>; + fn get(&self, key: &H::Out, prefix: Prefix) -> Result>; } // This implementation is used by normal storage trie clients. +#[cfg(feature = "std")] impl TrieBackendStorage for Arc> { type Overlay = PrefixedMemoryDB; - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { + fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { Storage::::get(self.deref(), key, prefix) } } @@ -353,7 +364,7 @@ impl TrieBackendStorage for Arc> { impl TrieBackendStorage for PrefixedMemoryDB { type Overlay = PrefixedMemoryDB; - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { + fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { Ok(hash_db::HashDB::get(self, key, prefix)) } } @@ -361,7 +372,7 @@ impl TrieBackendStorage for PrefixedMemoryDB { impl TrieBackendStorage for MemoryDB { type Overlay = MemoryDB; - fn get(&self, key: &H::Out, prefix: Prefix) -> Result, String> { + fn get(&self, key: &H::Out, prefix: Prefix) -> Result> { Ok(hash_db::HashDB::get(self, key, prefix)) } } diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 6b354f5f6e9f4..4f4cdb7d527b5 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -42,6 +42,8 @@ sp-transaction-pool = { version = "2.0.0-rc6", default-features = false, path = trie-db = { version = "0.22.0", default-features = false } parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.8.0-rc6", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } +sp-state-machine = { version = "0.8.0-rc6", default-features = false, path = "../../primitives/state-machine" } +sp-externalities = { version = "0.8.0-rc6", default-features = false, path = "../../primitives/externalities" } # 3rd party cfg-if = "0.1.10" @@ -52,7 +54,6 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] } sc-block-builder = { version = "0.8.0-rc6", path = "../../client/block-builder" } sc-executor = { version = "0.8.0-rc6", path = "../../client/executor" } substrate-test-runtime-client = { version = "2.0.0-rc6", path = "./client" } -sp-state-machine = { version = "0.8.0-rc6", path = "../../primitives/state-machine" } [build-dependencies] wasm-builder-runner = { version = "1.0.5", package = "substrate-wasm-builder-runner", path = "../../utils/wasm-builder-runner" } @@ -84,6 +85,8 @@ std = [ "sp-session/std", "sp-api/std", "sp-runtime/std", + "sp-externalities/std", + "sp-state-machine/std", "pallet-babe/std", "frame-system-rpc-runtime-api/std", "frame-system/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index f5e30de838a68..a7c1c261b5541 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -29,7 +29,7 @@ use codec::{Encode, Decode, Input, Error}; use sp_core::{offchain::KeyTypeId, ChangesTrieConfiguration, OpaqueMetadata, RuntimeDebug}; use sp_application_crypto::{ed25519, sr25519, ecdsa, RuntimeAppPublic}; use trie_db::{TrieMut, Trie}; -use sp_trie::PrefixedMemoryDB; +use sp_trie::{PrefixedMemoryDB, StorageProof}; use sp_trie::trie_types::{TrieDB, TrieDBMut}; use sp_api::{decl_runtime_apis, impl_runtime_apis}; @@ -335,6 +335,8 @@ cfg_if! { fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic); /// Run various tests against storage. fn test_storage(); + /// Check a witness. + fn test_witness(proof: StorageProof, root: crate::Hash); /// Test that ensures that we can call a function that takes multiple /// arguments. fn test_multiple_arguments(data: Vec, other: Vec, num: u32); @@ -384,6 +386,8 @@ cfg_if! { fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic); /// Run various tests against storage. fn test_storage(); + /// Check a witness. + fn test_witness(proof: StorageProof, root: crate::Hash); /// Test that ensures that we can call a function that takes multiple /// arguments. fn test_multiple_arguments(data: Vec, other: Vec, num: u32); @@ -684,6 +688,10 @@ cfg_if! { test_read_child_storage(); } + fn test_witness(proof: StorageProof, root: crate::Hash) { + test_witness(proof, root); + } + fn test_multiple_arguments(data: Vec, other: Vec, num: u32) { assert_eq!(&data[..], &other[..]); assert_eq!(data.len(), num as usize); @@ -926,6 +934,10 @@ cfg_if! { test_read_child_storage(); } + fn test_witness(proof: StorageProof, root: crate::Hash) { + test_witness(proof, root); + } + fn test_multiple_arguments(data: Vec, other: Vec, num: u32) { assert_eq!(&data[..], &other[..]); assert_eq!(data.len(), num as usize); @@ -1099,6 +1111,34 @@ fn test_read_child_storage() { assert_eq!(&v, &[0, 0, 0, 0]); } +fn test_witness(proof: StorageProof, root: crate::Hash) { + use sp_externalities::Externalities; + let db: sp_trie::MemoryDB = proof.into_memory_db(); + let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new( + db, + root, + ); + let mut overlay = sp_state_machine::OverlayedChanges::default(); + #[cfg(feature = "std")] + let mut offchain_overlay = Default::default(); + let mut cache = sp_state_machine::StorageTransactionCache::<_, _, BlockNumber>::default(); + let mut ext = sp_state_machine::Ext::new( + &mut overlay, + #[cfg(feature = "std")] + &mut offchain_overlay, + &mut cache, + &backend, + #[cfg(feature = "std")] + None, + #[cfg(feature = "std")] + None, + ); + assert!(ext.storage(b"value3").is_some()); + assert!(ext.storage_root().as_slice() == &root[..]); + ext.place_storage(vec![0], Some(vec![1])); + assert!(ext.storage_root().as_slice() != &root[..]); +} + #[cfg(test)] mod tests { use substrate_test_runtime_client::{ @@ -1157,4 +1197,33 @@ mod tests { runtime_api.test_storage(&block_id).unwrap(); } + + fn witness_backend() -> (sp_trie::MemoryDB, crate::Hash) { + use sp_trie::TrieMut; + let mut root = crate::Hash::default(); + let mut mdb = sp_trie::MemoryDB::::default(); + { + let mut trie = sp_trie::trie_types::TrieDBMut::new(&mut mdb, &mut root); + trie.insert(b"value3", &[142]).expect("insert failed"); + trie.insert(b"value4", &[124]).expect("insert failed"); + }; + (mdb, root) + } + + #[test] + fn witness_backend_works() { + let (db, root) = witness_backend(); + let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new( + db, + root, + ); + let proof = sp_state_machine::prove_read(backend, vec![b"value3"]).unwrap(); + let client = TestClientBuilder::new() + .set_execution_strategy(ExecutionStrategy::Both) + .build(); + let runtime_api = client.runtime_api(); + let block_id = BlockId::Number(client.chain_info().best_number); + + runtime_api.test_witness(&block_id, proof, root).unwrap(); + } }