#[cfg(feature = "std")]
use crate::trie_backend::TrieBackend;
use crate::{
trie_backend_essence::TrieBackendStorage, ChildStorageCollection, StorageCollection,
StorageKey, StorageValue, UsageInfo,
};
use codec::Encode;
use core::marker::PhantomData;
use hash_db::Hasher;
use sp_core::storage::{ChildInfo, StateVersion, TrackedStorageKey};
#[cfg(feature = "std")]
use sp_core::traits::RuntimeCode;
use sp_std::vec::Vec;
use sp_trie::PrefixedMemoryDB;
#[derive(Default)]
#[non_exhaustive]
pub struct IterArgs<'a> {
pub prefix: Option<&'a [u8]>,
pub start_at: Option<&'a [u8]>,
pub start_at_exclusive: bool,
pub child_info: Option<ChildInfo>,
pub stop_on_incomplete_database: bool,
}
pub trait StorageIterator<H>
where
H: Hasher,
{
type Backend;
type Error;
fn next_key(
&mut self,
backend: &Self::Backend,
) -> Option<core::result::Result<StorageKey, Self::Error>>;
fn next_pair(
&mut self,
backend: &Self::Backend,
) -> Option<core::result::Result<(StorageKey, StorageValue), Self::Error>>;
fn was_complete(&self) -> bool;
}
pub struct PairsIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H>,
{
backend: Option<&'a I::Backend>,
raw_iter: I,
_phantom: PhantomData<H>,
}
impl<'a, H, I> Iterator for PairsIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H>,
{
type Item = Result<(Vec<u8>, Vec<u8>), <I as StorageIterator<H>>::Error>;
fn next(&mut self) -> Option<Self::Item> {
self.raw_iter.next_pair(self.backend.as_ref()?)
}
}
impl<'a, H, I> Default for PairsIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H> + Default,
{
fn default() -> Self {
Self {
backend: Default::default(),
raw_iter: Default::default(),
_phantom: Default::default(),
}
}
}
impl<'a, H, I> PairsIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H> + Default,
{
#[cfg(feature = "std")]
pub(crate) fn was_complete(&self) -> bool {
self.raw_iter.was_complete()
}
}
pub struct KeysIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H>,
{
backend: Option<&'a I::Backend>,
raw_iter: I,
_phantom: PhantomData<H>,
}
impl<'a, H, I> Iterator for KeysIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H>,
{
type Item = Result<Vec<u8>, <I as StorageIterator<H>>::Error>;
fn next(&mut self) -> Option<Self::Item> {
self.raw_iter.next_key(self.backend.as_ref()?)
}
}
impl<'a, H, I> Default for KeysIter<'a, H, I>
where
H: Hasher,
I: StorageIterator<H> + Default,
{
fn default() -> Self {
Self {
backend: Default::default(),
raw_iter: Default::default(),
_phantom: Default::default(),
}
}
}
pub type BackendTransaction<H> = PrefixedMemoryDB<H>;
pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
type Error: super::Error;
type TrieBackendStorage: TrieBackendStorage<H>;
type RawIter: StorageIterator<H, Backend = Self, Error = Self::Error>;
fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>, Self::Error>;
fn storage_hash(&self, key: &[u8]) -> Result<Option<H::Out>, Self::Error>;
fn child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Result<Option<StorageValue>, Self::Error>;
fn child_storage_hash(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Result<Option<H::Out>, Self::Error>;
fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
Ok(self.storage_hash(key)?.is_some())
}
fn exists_child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Result<bool, Self::Error> {
Ok(self.child_storage_hash(child_info, key)?.is_some())
}
fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>, Self::Error>;
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Result<Option<StorageKey>, Self::Error>;
fn storage_root<'a>(
&self,
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
state_version: StateVersion,
) -> (H::Out, BackendTransaction<H>)
where
H::Out: Ord;
fn child_storage_root<'a>(
&self,
child_info: &ChildInfo,
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
state_version: StateVersion,
) -> (H::Out, bool, BackendTransaction<H>)
where
H::Out: Ord;
fn raw_iter(&self, args: IterArgs) -> Result<Self::RawIter, Self::Error>;
fn pairs<'a>(&'a self, args: IterArgs) -> Result<PairsIter<'a, H, Self::RawIter>, Self::Error> {
Ok(PairsIter {
backend: Some(self),
raw_iter: self.raw_iter(args)?,
_phantom: Default::default(),
})
}
fn keys<'a>(&'a self, args: IterArgs) -> Result<KeysIter<'a, H, Self::RawIter>, Self::Error> {
Ok(KeysIter {
backend: Some(self),
raw_iter: self.raw_iter(args)?,
_phantom: Default::default(),
})
}
fn full_storage_root<'a>(
&self,
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
child_deltas: impl Iterator<
Item = (&'a ChildInfo, impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>),
>,
state_version: StateVersion,
) -> (H::Out, BackendTransaction<H>)
where
H::Out: Ord + Encode,
{
let mut txs = BackendTransaction::default();
let mut child_roots: Vec<_> = Default::default();
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)
}
fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats);
fn usage_info(&self) -> UsageInfo;
fn wipe(&self) -> Result<(), Self::Error> {
unimplemented!()
}
fn commit(
&self,
_: H::Out,
_: BackendTransaction<H>,
_: StorageCollection,
_: ChildStorageCollection,
) -> Result<(), Self::Error> {
unimplemented!()
}
fn read_write_count(&self) -> (u32, u32, u32, u32) {
unimplemented!()
}
fn reset_read_write_count(&self) {
unimplemented!()
}
fn get_whitelist(&self) -> Vec<TrackedStorageKey> {
Default::default()
}
fn set_whitelist(&self, _: Vec<TrackedStorageKey>) {}
fn proof_size(&self) -> Option<u32> {
unimplemented!()
}
fn get_read_and_written_keys(&self) -> Vec<(Vec<u8>, u32, u32, bool)> {
unimplemented!()
}
}
#[cfg(feature = "std")]
pub trait AsTrieBackend<H: Hasher, C = sp_trie::cache::LocalTrieCache<H>> {
type TrieBackendStorage: TrieBackendStorage<H>;
fn as_trie_backend(&self) -> &TrieBackend<Self::TrieBackendStorage, H, C>;
}
#[cfg(feature = "std")]
pub struct BackendRuntimeCode<'a, B, H> {
backend: &'a B,
_marker: PhantomData<H>,
}
#[cfg(feature = "std")]
impl<'a, B: Backend<H>, H: Hasher> sp_core::traits::FetchRuntimeCode
for BackendRuntimeCode<'a, B, H>
{
fn fetch_runtime_code(&self) -> Option<std::borrow::Cow<[u8]>> {
self.backend
.storage(sp_core::storage::well_known_keys::CODE)
.ok()
.flatten()
.map(Into::into)
}
}
#[cfg(feature = "std")]
impl<'a, B: Backend<H>, H: Hasher> BackendRuntimeCode<'a, B, H>
where
H::Out: Encode,
{
pub fn new(backend: &'a B) -> Self {
Self { backend, _marker: PhantomData }
}
pub fn runtime_code(&self) -> Result<RuntimeCode, &'static str> {
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 })
}
}