// This file is part of Substrate. // Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! State machine backends. These manage the code and storage of contracts. #[cfg(feature = "std")] use crate::trie_backend::TrieBackend; use crate::{ trie_backend_essence::TrieBackendStorage, ChildStorageCollection, StorageCollection, StorageKey, StorageValue, UsageInfo, }; use codec::Encode; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey}; #[cfg(feature = "std")] use sp_core::traits::RuntimeCode; use sp_std::vec::Vec; /// 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: sp_std::fmt::Debug { /// An error type when fetching data is not possible. type Error: super::Error; /// Storage changes to be applied if committing type Transaction: Consolidate + Default + Send; /// Type of trie backend storage. type TrieBackendStorage: TrieBackendStorage; /// Get keyed storage or None if there is nothing associated. fn storage(&self, key: &[u8]) -> Result, Self::Error>; /// Get keyed storage value hash or None if there is nothing associated. fn storage_hash(&self, key: &[u8]) -> Result, Self::Error>; /// Get keyed child storage or None if there is nothing associated. fn child_storage( &self, child_info: &ChildInfo, key: &[u8], ) -> Result, Self::Error>; /// Get child keyed storage value hash or None if there is nothing associated. fn child_storage_hash( &self, child_info: &ChildInfo, key: &[u8], ) -> Result, Self::Error>; /// true if a key exists in storage. fn exists_storage(&self, key: &[u8]) -> Result { Ok(self.storage_hash(key)?.is_some()) } /// true if a key exists in child storage. fn exists_child_storage( &self, child_info: &ChildInfo, key: &[u8], ) -> Result { Ok(self.child_storage_hash(child_info, key)?.is_some()) } /// Return the next key in storage in lexicographic order or `None` if there is no value. fn next_storage_key(&self, key: &[u8]) -> Result, Self::Error>; /// Return the next key in child storage in lexicographic order or `None` if there is no value. fn next_child_storage_key( &self, child_info: &ChildInfo, key: &[u8], ) -> Result, Self::Error>; /// Iterate over storage starting at key, for a given prefix and child trie. /// Aborts as soon as `f` returns false. /// Warning, this fails at first error when usual iteration skips errors. /// If `allow_missing` is true, iteration stops when it reaches a missing trie node. /// Otherwise an error is produced. /// /// Returns `true` if trie end is reached. fn apply_to_key_values_while, Vec) -> bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, start_at: Option<&[u8]>, f: F, allow_missing: bool, ) -> Result; /// Retrieve all entries keys of storage and call `f` for each of those keys. /// Aborts as soon as `f` returns false. fn apply_to_keys_while bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, start_at: Option<&[u8]>, f: F, ); /// Retrieve all entries keys which start with the given prefix and /// call `f` for each of those keys. fn for_keys_with_prefix(&self, prefix: &[u8], mut f: F) { self.for_key_values_with_prefix(prefix, |k, _v| f(k)) } /// Retrieve all entries keys and values of which start with the given prefix and /// call `f` for each of those keys. fn for_key_values_with_prefix(&self, prefix: &[u8], f: F); /// Retrieve all child entries keys which start with the given prefix and /// call `f` for each of those keys. fn for_child_keys_with_prefix( &self, child_info: &ChildInfo, prefix: &[u8], f: F, ); /// Calculate the storage root, with given delta over what is already stored in /// the backend, and produce a "transaction" that can be used to commit. /// Does not include child storage updates. fn storage_root<'a>( &self, delta: impl Iterator)>, state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord; /// Calculate the child storage root, with given delta over what is already stored in /// the backend, and produce a "transaction" that can be used to commit. The second argument /// is true if child storage root equals default storage root. fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, state_version: StateVersion, ) -> (H::Out, bool, Self::Transaction) where H::Out: Ord; /// Get all key/value pairs into a Vec. fn pairs(&self) -> Vec<(StorageKey, StorageValue)>; /// Get all keys with given prefix fn keys(&self, prefix: &[u8]) -> Vec { let mut all = Vec::new(); self.for_keys_with_prefix(prefix, |k| all.push(k.to_vec())); all } /// Get all keys of child storage with given prefix fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec { let mut all = Vec::new(); self.for_child_keys_with_prefix(child_info, prefix, |k| all.push(k.to_vec())); all } /// Calculate the storage root, with given delta over what is already stored /// in the backend, and produce a "transaction" that can be used to commit. /// Does include child storage updates. fn full_storage_root<'a>( &self, delta: impl Iterator)>, child_deltas: impl Iterator< Item = (&'a ChildInfo, impl Iterator)>), >, state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord + Encode, { let mut txs: Self::Transaction = Default::default(); let mut child_roots: Vec<_> = Default::default(); // child first for (child_info, child_delta) in child_deltas { let (child_root, empty, child_txs) = self.child_storage_root(child_info, child_delta, state_version); let prefixed_storage_key = child_info.prefixed_storage_key(); txs.consolidate(child_txs); if empty { child_roots.push((prefixed_storage_key.into_inner(), None)); } else { child_roots.push((prefixed_storage_key.into_inner(), Some(child_root.encode()))); } } let (root, parent_txs) = self.storage_root( delta .map(|(k, v)| (k, v.as_ref().map(|v| &v[..]))) .chain(child_roots.iter().map(|(k, v)| (&k[..], v.as_ref().map(|v| &v[..])))), state_version, ); txs.consolidate(parent_txs); (root, txs) } /// Register stats from overlay of state machine. /// /// By default nothing is registered. fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats); /// Query backend usage statistics (i/o, memory) /// /// Not all implementations are expected to be able to do this. In the /// case when they don't, empty statistics is returned. fn usage_info(&self) -> UsageInfo; /// Wipe the state database. fn wipe(&self) -> Result<(), Self::Error> { unimplemented!() } /// Commit given transaction to storage. fn commit( &self, _: H::Out, _: Self::Transaction, _: StorageCollection, _: ChildStorageCollection, ) -> Result<(), Self::Error> { unimplemented!() } /// Get the read/write count of the db fn read_write_count(&self) -> (u32, u32, u32, u32) { unimplemented!() } /// Get the read/write count of the db fn reset_read_write_count(&self) { unimplemented!() } /// Get the whitelist for tracking db reads/writes fn get_whitelist(&self) -> Vec { Default::default() } /// Update the whitelist for tracking db reads/writes fn set_whitelist(&self, _: Vec) {} /// Estimate proof size fn proof_size(&self) -> Option { unimplemented!() } /// Extend storage info for benchmarking db fn get_read_and_written_keys(&self) -> Vec<(Vec, u32, u32, bool)> { unimplemented!() } } /// Something that can be converted into a [`TrieBackend`]. #[cfg(feature = "std")] pub trait AsTrieBackend> { /// Type of trie backend storage. type TrieBackendStorage: TrieBackendStorage; /// Return the type as [`TrieBackend`]. fn as_trie_backend(&self) -> &TrieBackend; } /// Trait that allows consolidate two transactions together. pub trait Consolidate { /// Consolidate two transactions into one. fn consolidate(&mut self, other: Self); } impl Consolidate for () { fn consolidate(&mut self, _: Self) { () } } impl Consolidate for Vec<(Option, StorageCollection)> { fn consolidate(&mut self, mut other: Self) { self.append(&mut other); } } impl Consolidate for sp_trie::GenericMemoryDB where H: Hasher, KF: sp_trie::KeyFunction, { fn consolidate(&mut self, other: Self) { sp_trie::GenericMemoryDB::consolidate(self, other) } } /// 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> { fn fetch_runtime_code(&self) -> Option> { self.backend .storage(sp_core::storage::well_known_keys::CODE) .ok() .flatten() .map(Into::into) } } #[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 { Self { backend, _marker: std::marker::PhantomData } } /// Return the [`RuntimeCode`] build from the wrapped `backend`. pub fn runtime_code(&self) -> Result { let hash = self .backend .storage_hash(sp_core::storage::well_known_keys::CODE) .ok() .flatten() .ok_or("`:code` hash not found")? .encode(); let heap_pages = self .backend .storage(sp_core::storage::well_known_keys::HEAP_PAGES) .ok() .flatten() .and_then(|d| codec::Decode::decode(&mut &d[..]).ok()); Ok(RuntimeCode { code_fetcher: self, hash, heap_pages }) } }