Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
@@ -17,19 +17,16 @@
//! State machine backends. These manage the code and storage of contracts.
use hash_db::Hasher;
use codec::{Decode, Encode};
use sp_core::{
storage::{ChildInfo, well_known_keys, TrackedStorageKey}
};
use crate::{
trie_backend::TrieBackend,
trie_backend_essence::TrieBackendStorage,
UsageInfo, StorageKey, StorageValue, StorageCollection, ChildStorageCollection,
trie_backend::TrieBackend, trie_backend_essence::TrieBackendStorage, ChildStorageCollection,
StorageCollection, StorageKey, StorageValue, UsageInfo,
};
use sp_std::vec::Vec;
use codec::{Decode, Encode};
use hash_db::Hasher;
use sp_core::storage::{well_known_keys, ChildInfo, 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.
@@ -90,7 +87,7 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8]
key: &[u8],
) -> Result<Option<StorageKey>, Self::Error>;
/// Iterate over storage starting at key, for a given prefix and child trie.
@@ -128,7 +125,6 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
/// call `f` for each of those keys.
fn for_key_values_with_prefix<F: FnMut(&[u8], &[u8])>(&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<F: FnMut(&[u8])>(
@@ -143,8 +139,10 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
/// Does not include child storage updates.
fn storage_root<'a>(
&self,
delta: impl Iterator<Item=(&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, Self::Transaction) where H::Out: Ord;
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
) -> (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
@@ -152,8 +150,10 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
fn child_storage_root<'a>(
&self,
child_info: &ChildInfo,
delta: impl Iterator<Item=(&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, bool, Self::Transaction) where H::Out: Ord;
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, bool, Self::Transaction)
where
H::Out: Ord;
/// Get all key/value pairs into a Vec.
fn pairs(&self) -> Vec<(StorageKey, StorageValue)>;
@@ -166,11 +166,7 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
}
/// Get all keys of child storage with given prefix
fn child_keys(
&self,
child_info: &ChildInfo,
prefix: &[u8],
) -> Vec<StorageKey> {
fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec<StorageKey> {
let mut all = Vec::new();
self.for_child_keys_with_prefix(child_info, prefix, |k| all.push(k.to_vec()));
all
@@ -186,18 +182,19 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
/// Does include child storage updates.
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]>)>,
)>,
) -> (H::Out, Self::Transaction) where H::Out: Ord + Encode {
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
child_deltas: impl Iterator<
Item = (&'a ChildInfo, impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>),
>,
) -> (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);
let (child_root, empty, child_txs) = self.child_storage_root(&child_info, child_delta);
let prefixed_storage_key = child_info.prefixed_storage_key();
txs.consolidate(child_txs);
if empty {
@@ -206,13 +203,10 @@ pub trait Backend<H: Hasher>: sp_std::fmt::Debug {
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[..])))
)
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[..])))),
);
txs.consolidate(parent_txs);
(root, txs)
@@ -286,10 +280,7 @@ impl Consolidate for () {
}
}
impl Consolidate for Vec<(
Option<ChildInfo>,
StorageCollection,
)> {
impl Consolidate for Vec<(Option<ChildInfo>, StorageCollection)> {
fn consolidate(&mut self, mut other: Self) {
self.append(&mut other);
}
@@ -303,12 +294,15 @@ impl<H: Hasher, KF: sp_trie::KeyFunction<H>> Consolidate for sp_trie::GenericMem
/// Insert input pairs into memory db.
#[cfg(test)]
pub(crate) fn insert_into_memory_db<H, I>(mdb: &mut sp_trie::MemoryDB<H>, input: I) -> Option<H::Out>
where
H: Hasher,
I: IntoIterator<Item=(StorageKey, StorageValue)>,
pub(crate) fn insert_into_memory_db<H, I>(
mdb: &mut sp_trie::MemoryDB<H>,
input: I,
) -> Option<H::Out>
where
H: Hasher,
I: IntoIterator<Item = (StorageKey, StorageValue)>,
{
use sp_trie::{TrieMut, trie_types::TrieDBMut};
use sp_trie::{trie_types::TrieDBMut, TrieMut};
let mut root = <H as Hasher>::Out::default();
{
@@ -316,7 +310,7 @@ pub(crate) fn insert_into_memory_db<H, I>(mdb: &mut sp_trie::MemoryDB<H>, input:
for (key, value) in input {
if let Err(e) = trie.insert(&key, &value) {
log::warn!(target: "trie", "Failed to write to trie: {}", e);
return None;
return None
}
}
}
@@ -332,8 +326,8 @@ pub struct BackendRuntimeCode<'a, B, H> {
}
#[cfg(feature = "std")]
impl<'a, B: Backend<H>, H: Hasher> sp_core::traits::FetchRuntimeCode for
BackendRuntimeCode<'a, B, H>
impl<'a, B: Backend<H>, H: Hasher> sp_core::traits::FetchRuntimeCode
for BackendRuntimeCode<'a, B, H>
{
fn fetch_runtime_code<'b>(&'b self) -> Option<std::borrow::Cow<'b, [u8]>> {
self.backend.storage(well_known_keys::CODE).ok().flatten().map(Into::into)
@@ -341,23 +335,27 @@ impl<'a, B: Backend<H>, H: Hasher> sp_core::traits::FetchRuntimeCode for
}
#[cfg(feature = "std")]
impl<'a, B: Backend<H>, H: Hasher> BackendRuntimeCode<'a, B, H> where H::Out: Encode {
impl<'a, B: Backend<H>, 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,
}
Self { backend, _marker: std::marker::PhantomData }
}
/// Return the [`RuntimeCode`] build from the wrapped `backend`.
pub fn runtime_code(&self) -> Result<RuntimeCode, &'static str> {
let hash = self.backend.storage_hash(well_known_keys::CODE)
let hash = self
.backend
.storage_hash(well_known_keys::CODE)
.ok()
.flatten()
.ok_or("`:code` hash not found")?
.encode();
let heap_pages = self.backend.storage(well_known_keys::HEAP_PAGES)
let heap_pages = self
.backend
.storage(well_known_keys::HEAP_PAGES)
.ok()
.flatten()
.and_then(|d| Decode::decode(&mut &d[..]).ok());
+81 -72
View File
@@ -17,23 +17,25 @@
//! Basic implementation for Externalities.
use std::{
collections::BTreeMap, any::{TypeId, Any}, iter::FromIterator, ops::Bound,
};
use crate::{Backend, StorageKey, StorageValue};
use codec::Encode;
use hash_db::Hasher;
use sp_trie::{TrieConfiguration, empty_child_trie_root};
use sp_trie::trie_types::Layout;
use log::warn;
use sp_core::{
storage::{
well_known_keys::is_child_storage_key, Storage,
ChildInfo, StorageChild, TrackedStorageKey,
well_known_keys::is_child_storage_key, ChildInfo, Storage, StorageChild, TrackedStorageKey,
},
traits::Externalities, Blake2Hasher,
traits::Externalities,
Blake2Hasher,
};
use sp_externalities::{Extension, Extensions};
use sp_trie::{empty_child_trie_root, trie_types::Layout, TrieConfiguration};
use std::{
any::{Any, TypeId},
collections::BTreeMap,
iter::FromIterator,
ops::Bound,
};
use log::warn;
use codec::Encode;
use sp_externalities::{Extensions, Extension};
/// Simple Map-based Externalities impl.
#[derive(Debug)]
@@ -105,13 +107,13 @@ impl BasicExternalities {
impl PartialEq for BasicExternalities {
fn eq(&self, other: &BasicExternalities) -> bool {
self.inner.top.eq(&other.inner.top)
&& self.inner.children_default.eq(&other.inner.children_default)
self.inner.top.eq(&other.inner.top) &&
self.inner.children_default.eq(&other.inner.children_default)
}
}
impl FromIterator<(StorageKey, StorageValue)> for BasicExternalities {
fn from_iter<I: IntoIterator<Item=(StorageKey, StorageValue)>>(iter: I) -> Self {
fn from_iter<I: IntoIterator<Item = (StorageKey, StorageValue)>>(iter: I) -> Self {
let mut t = Self::default();
t.inner.top.extend(iter);
t
@@ -119,16 +121,15 @@ impl FromIterator<(StorageKey, StorageValue)> for BasicExternalities {
}
impl Default for BasicExternalities {
fn default() -> Self { Self::new(Default::default()) }
fn default() -> Self {
Self::new(Default::default())
}
}
impl From<BTreeMap<StorageKey, StorageValue>> for BasicExternalities {
fn from(hashmap: BTreeMap<StorageKey, StorageValue>) -> Self {
BasicExternalities {
inner: Storage {
top: hashmap,
children_default: Default::default(),
},
inner: Storage { top: hashmap, children_default: Default::default() },
extensions: Default::default(),
}
}
@@ -145,20 +146,15 @@ impl Externalities for BasicExternalities {
self.storage(key).map(|v| Blake2Hasher::hash(&v).encode())
}
fn child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageValue> {
self.inner.children_default.get(child_info.storage_key())
.and_then(|child| child.data.get(key)).cloned()
fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageValue> {
self.inner
.children_default
.get(child_info.storage_key())
.and_then(|child| child.data.get(key))
.cloned()
}
fn child_storage_hash(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>> {
fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>> {
self.child_storage(child_info, key).map(|v| Blake2Hasher::hash(&v).encode())
}
@@ -167,25 +163,27 @@ impl Externalities for BasicExternalities {
self.inner.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned()
}
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageKey> {
fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageKey> {
let range = (Bound::Excluded(key), Bound::Unbounded);
self.inner.children_default.get(child_info.storage_key())
self.inner
.children_default
.get(child_info.storage_key())
.and_then(|child| child.data.range::<[u8], _>(range).next().map(|(k, _)| k).cloned())
}
fn place_storage(&mut self, key: StorageKey, maybe_value: Option<StorageValue>) {
if is_child_storage_key(&key) {
warn!(target: "trie", "Refuse to set child storage key via main storage");
return;
return
}
match maybe_value {
Some(value) => { self.inner.top.insert(key, value); }
None => { self.inner.top.remove(&key); }
Some(value) => {
self.inner.top.insert(key, value);
},
None => {
self.inner.top.remove(&key);
},
}
}
@@ -195,7 +193,10 @@ impl Externalities for BasicExternalities {
key: StorageKey,
value: Option<StorageValue>,
) {
let child_map = self.inner.children_default.entry(child_info.storage_key().to_vec())
let child_map = self
.inner
.children_default
.entry(child_info.storage_key().to_vec())
.or_insert_with(|| StorageChild {
data: Default::default(),
child_info: child_info.to_owned(),
@@ -207,12 +208,13 @@ impl Externalities for BasicExternalities {
}
}
fn kill_child_storage(
&mut self,
child_info: &ChildInfo,
_limit: Option<u32>,
) -> (bool, u32) {
let num_removed = self.inner.children_default.remove(child_info.storage_key()).map(|c| c.data.len()).unwrap_or(0);
fn kill_child_storage(&mut self, child_info: &ChildInfo, _limit: Option<u32>) -> (bool, u32) {
let num_removed = self
.inner
.children_default
.remove(child_info.storage_key())
.map(|c| c.data.len())
.unwrap_or(0);
(true, num_removed as u32)
}
@@ -222,10 +224,13 @@ impl Externalities for BasicExternalities {
target: "trie",
"Refuse to clear prefix that is part of child storage key via main storage"
);
return (false, 0);
return (false, 0)
}
let to_remove = self.inner.top.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
let to_remove = self
.inner
.top
.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
.map(|(k, _)| k)
.take_while(|k| k.starts_with(prefix))
.cloned()
@@ -245,7 +250,9 @@ impl Externalities for BasicExternalities {
_limit: Option<u32>,
) -> (bool, u32) {
if let Some(child) = self.inner.children_default.get_mut(child_info.storage_key()) {
let to_remove = child.data.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
let to_remove = child
.data
.range::<[u8], _>((Bound::Included(prefix), Bound::Unbounded))
.map(|(k, _)| k)
.take_while(|k| k.starts_with(prefix))
.cloned()
@@ -261,20 +268,19 @@ impl Externalities for BasicExternalities {
}
}
fn storage_append(
&mut self,
key: Vec<u8>,
value: Vec<u8>,
) {
fn storage_append(&mut self, key: Vec<u8>, value: Vec<u8>) {
let current = self.inner.top.entry(key).or_default();
crate::ext::StorageAppend::new(current).append(value);
}
fn storage_root(&mut self) -> Vec<u8> {
let mut top = self.inner.top.clone();
let prefixed_keys: Vec<_> = self.inner.children_default.iter().map(|(_k, v)| {
(v.child_info.prefixed_storage_key(), v.child_info.clone())
}).collect();
let prefixed_keys: Vec<_> = self
.inner
.children_default
.iter()
.map(|(_k, v)| (v.child_info.prefixed_storage_key(), v.child_info.clone()))
.collect();
// Single child trie implementation currently allows using the same child
// empty root for all child trie. Using null storage key until multiple
// type of child trie support.
@@ -291,17 +297,16 @@ impl Externalities for BasicExternalities {
Layout::<Blake2Hasher>::trie_root(self.inner.top.clone()).as_ref().into()
}
fn child_storage_root(
&mut self,
child_info: &ChildInfo,
) -> Vec<u8> {
fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec<u8> {
if let Some(child) = self.inner.children_default.get(child_info.storage_key()) {
let delta = child.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref())));
crate::in_memory_backend::new_in_mem::<Blake2Hasher>()
.child_storage_root(&child.child_info, delta).0
.child_storage_root(&child.child_info, delta)
.0
} else {
empty_child_trie_root::<Layout<Blake2Hasher>>()
}.encode()
}
.encode()
}
fn storage_changes_root(&mut self, _parent: &[u8]) -> Result<Option<Vec<u8>>, ()> {
@@ -358,7 +363,10 @@ impl sp_externalities::ExtensionStore for BasicExternalities {
self.extensions.register_with_type_id(type_id, extension)
}
fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), sp_externalities::Error> {
fn deregister_extension_by_type_id(
&mut self,
type_id: TypeId,
) -> Result<(), sp_externalities::Error> {
if self.extensions.deregister(type_id) {
Ok(())
} else {
@@ -370,10 +378,11 @@ impl sp_externalities::ExtensionStore for BasicExternalities {
#[cfg(test)]
mod tests {
use super::*;
use sp_core::map;
use sp_core::storage::{Storage, StorageChild};
use sp_core::storage::well_known_keys::CODE;
use hex_literal::hex;
use sp_core::{
map,
storage::{well_known_keys::CODE, Storage, StorageChild},
};
#[test]
fn commit_should_work() {
@@ -381,7 +390,8 @@ mod tests {
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
const ROOT: [u8; 32] =
hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
assert_eq!(&ext.storage_root()[..], &ROOT);
}
@@ -407,7 +417,7 @@ mod tests {
data: map![ b"doe".to_vec() => b"reindeer".to_vec() ],
child_info: child_info.to_owned(),
}
]
],
});
assert_eq!(ext.child_storage(child_info, b"doe"), Some(b"reindeer".to_vec()));
@@ -437,10 +447,9 @@ mod tests {
],
child_info: child_info.to_owned(),
}
]
],
});
let res = ext.kill_child_storage(child_info, None);
assert_eq!(res, (true, 3));
}
File diff suppressed because it is too large Load Diff
@@ -78,20 +78,20 @@ pub(crate) struct IncompleteCachedBuildData<N> {
}
impl<H, N> BuildCache<H, N>
where
N: Eq + ::std::hash::Hash,
H: Eq + ::std::hash::Hash + Clone,
where
N: Eq + ::std::hash::Hash,
H: Eq + ::std::hash::Hash + Clone,
{
/// Create new changes trie build cache.
pub fn new() -> Self {
BuildCache {
roots_by_number: HashMap::new(),
changed_keys: HashMap::new(),
}
BuildCache { roots_by_number: HashMap::new(), changed_keys: HashMap::new() }
}
/// Get cached changed keys for changes trie with given root.
pub fn get(&self, root: &H) -> Option<&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>> {
pub fn get(
&self,
root: &H,
) -> Option<&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>> {
self.changed_keys.get(&root)
}
@@ -158,7 +158,9 @@ impl<N> IncompleteCacheAction<N> {
pub(crate) fn set_digest_input_blocks(self, digest_input_blocks: Vec<N>) -> Self {
match self {
IncompleteCacheAction::CacheBuildData(build_data) =>
IncompleteCacheAction::CacheBuildData(build_data.set_digest_input_blocks(digest_input_blocks)),
IncompleteCacheAction::CacheBuildData(
build_data.set_digest_input_blocks(digest_input_blocks),
),
IncompleteCacheAction::Clear => IncompleteCacheAction::Clear,
}
}
@@ -180,10 +182,7 @@ impl<N> IncompleteCacheAction<N> {
impl<N> IncompleteCachedBuildData<N> {
/// Create new cached data.
pub(crate) fn new() -> Self {
IncompleteCachedBuildData {
digest_input_blocks: Vec::new(),
changed_keys: HashMap::new(),
}
IncompleteCachedBuildData { digest_input_blocks: Vec::new(), changed_keys: HashMap::new() }
}
fn complete<H>(self, block: N, trie_root: H) -> CachedBuildData<H, N> {
@@ -232,30 +231,42 @@ mod tests {
#[test]
fn obsolete_entries_are_purged_when_new_ct_is_built() {
let mut cache = BuildCache::<u32, u32>::new();
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![1]].into_iter().collect())
.complete(1, 1)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![2]].into_iter().collect())
.complete(2, 2)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![3]].into_iter().collect())
.complete(3, 3)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![1]].into_iter().collect())
.complete(1, 1),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![2]].into_iter().collect())
.complete(2, 2),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![3]].into_iter().collect())
.complete(3, 3),
));
assert_eq!(cache.changed_keys.len(), 3);
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.set_digest_input_blocks(vec![1, 2, 3])
.complete(4, 4)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.set_digest_input_blocks(vec![1, 2, 3])
.complete(4, 4),
));
assert_eq!(cache.changed_keys.len(), 1);
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![8]].into_iter().collect())
.complete(8, 8)));
cache.perform(CacheAction::CacheBuildData(IncompleteCachedBuildData::new()
.insert(None, vec![vec![12]].into_iter().collect())
.complete(12, 12)));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![8]].into_iter().collect())
.complete(8, 8),
));
cache.perform(CacheAction::CacheBuildData(
IncompleteCachedBuildData::new()
.insert(None, vec![vec![12]].into_iter().collect())
.complete(12, 12),
));
assert_eq!(cache.changed_keys.len(), 3);
@@ -18,8 +18,8 @@
//! Structures and functions to return blocks whose changes are to be included
//! in given block's changes trie.
use crate::changes_trie::{BlockNumber, ConfigurationRange};
use num_traits::Zero;
use crate::changes_trie::{ConfigurationRange, BlockNumber};
/// Returns iterator of OTHER blocks that are required for inclusion into
/// changes trie of given block. Blocks are guaranteed to be returned in
@@ -31,13 +31,19 @@ pub fn digest_build_iterator<'a, Number: BlockNumber>(
block: Number,
) -> DigestBuildIterator<Number> {
// prepare digest build parameters
let (_, _, digest_step) = match config.config.digest_level_at_block(config.zero, block.clone()) {
let (_, _, digest_step) = match config.config.digest_level_at_block(config.zero, block.clone())
{
Some((current_level, digest_interval, digest_step)) =>
(current_level, digest_interval, digest_step),
None => return DigestBuildIterator::empty(),
};
DigestBuildIterator::new(block.clone(), config.end.unwrap_or(block), config.config.digest_interval, digest_step)
DigestBuildIterator::new(
block.clone(),
config.end.unwrap_or(block),
config.config.digest_interval,
digest_step,
)
}
/// Changes trie build iterator that returns numbers of OTHER blocks that are
@@ -56,7 +62,6 @@ pub struct DigestBuildIterator<Number: BlockNumber> {
max_step: u32,
// Mutable data below:
/// Step of current blocks range.
current_step: u32,
/// Reverse step of current blocks range.
@@ -98,7 +103,7 @@ impl<Number: BlockNumber> Iterator for DigestBuildIterator<Number> {
if let Some(next) = self.current_range.as_mut().and_then(|iter| iter.next()) {
if next < self.end {
self.last_block = Some(next.clone());
return Some(next);
return Some(next)
}
}
@@ -112,14 +117,16 @@ impl<Number: BlockNumber> Iterator for DigestBuildIterator<Number> {
self.current_step_reverse * self.digest_interval
};
if next_step_reverse > self.max_step {
return None;
return None
}
self.current_step_reverse = next_step_reverse;
self.current_range = Some(BlocksRange::new(
match self.last_block.clone() {
Some(last_block) => last_block + self.current_step.into(),
None => self.block.clone() - (self.current_step * self.digest_interval - self.current_step).into(),
None =>
self.block.clone() -
(self.current_step * self.digest_interval - self.current_step).into(),
},
self.block.clone(),
self.current_step.into(),
@@ -143,11 +150,7 @@ struct BlocksRange<Number: BlockNumber> {
impl<Number: BlockNumber> BlocksRange<Number> {
pub fn new(begin: Number, end: Number, step: Number) -> Self {
BlocksRange {
current: begin,
end,
step,
}
BlocksRange { current: begin, end, step }
}
}
@@ -156,7 +159,7 @@ impl<Number: BlockNumber> Iterator for BlocksRange<Number> {
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
return None
}
let current = Some(self.current.clone());
@@ -167,8 +170,8 @@ impl<Number: BlockNumber> Iterator for BlocksRange<Number> {
#[cfg(test)]
mod tests {
use crate::changes_trie::Configuration;
use super::*;
use crate::changes_trie::Configuration;
fn digest_build_iterator(
digest_interval: u32,
@@ -179,10 +182,7 @@ mod tests {
) -> DigestBuildIterator<u64> {
super::digest_build_iterator(
ConfigurationRange {
config: &Configuration {
digest_interval,
digest_levels,
},
config: &Configuration { digest_interval, digest_levels },
zero,
end,
},
@@ -215,9 +215,21 @@ mod tests {
fn test_with_zero(zero: u64) {
let empty = (0, 0, 0);
assert_eq!(digest_build_iterator_basic(4, 16, zero, zero + 0), empty, "block is 0");
assert_eq!(digest_build_iterator_basic(0, 16, zero, zero + 64), empty, "digest_interval is 0");
assert_eq!(digest_build_iterator_basic(1, 16, zero, zero + 64), empty, "digest_interval is 1");
assert_eq!(digest_build_iterator_basic(4, 0, zero, zero + 64), empty, "digest_levels is 0");
assert_eq!(
digest_build_iterator_basic(0, 16, zero, zero + 64),
empty,
"digest_interval is 0"
);
assert_eq!(
digest_build_iterator_basic(1, 16, zero, zero + 64),
empty,
"digest_interval is 1"
);
assert_eq!(
digest_build_iterator_basic(4, 0, zero, zero + 64),
empty,
"digest_levels is 0"
);
assert_eq!(
digest_build_iterator_basic(4, 16, zero, zero + 1),
empty,
@@ -238,12 +250,11 @@ mod tests {
empty,
"digest is not required for this block",
);
assert_eq!(digest_build_iterator_basic(
::std::u32::MAX / 2 + 1,
16,
zero,
::std::u64::MAX,
), empty, "digest_interval * 2 is greater than u64::MAX");
assert_eq!(
digest_build_iterator_basic(::std::u32::MAX / 2 + 1, 16, zero, ::std::u64::MAX,),
empty,
"digest_interval * 2 is greater than u64::MAX"
);
}
test_with_zero(0);
@@ -326,18 +337,37 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 1, zero, zero + 16, None),
assert_eq!(
digest_build_iterator_blocks(16, 1, zero, zero + 16, None),
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 1, zero, zero + 256, None),
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 1, zero, zero + 256, None),
[241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 32, None),
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 32, None),
[17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
.iter().map(|item| zero + item).collect::<Vec<_>>());
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4080, None),
[4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079]
.iter().map(|item| zero + item).collect::<Vec<_>>());
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4080, None),
[
4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077,
4078, 4079
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>()
);
}
test_with_zero(0);
@@ -348,21 +378,30 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_and_level2_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 256, None),
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 256, None),
[
// level2 points to previous 16-1 level1 digests:
16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240,
// level2 is a level1 digest of 16-1 previous blocks:
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
assert_eq!(digest_build_iterator_blocks(16, 2, zero, zero + 4096, None),
assert_eq!(
digest_build_iterator_blocks(16, 2, zero, zero + 4096, None),
[
// level2 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080,
// level2 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048,
4064, 4080, // level2 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093,
4094, 4095,
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -374,15 +413,20 @@ mod tests {
#[test]
fn digest_iterator_returns_level1_and_level2_and_level3_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, None),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, None),
[
// level3 points to previous 16-1 level2 digests:
256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840,
// level3 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048, 4064, 4080,
// level3 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, // level3 points to previous 16-1 level1 digests:
3856, 3872, 3888, 3904, 3920, 3936, 3952, 3968, 3984, 4000, 4016, 4032, 4048,
4064, 4080, // level3 is a level1 digest of 16-1 previous blocks:
4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093,
4094, 4095,
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -394,7 +438,8 @@ mod tests {
#[test]
fn digest_iterator_returns_skewed_digest_blocks() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1338)),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1338)),
[
// level3 MUST point to previous 16-1 level2 digests, BUT there are only 5:
256, 512, 768, 1024, 1280,
@@ -402,7 +447,10 @@ mod tests {
1296, 1312, 1328,
// level3 MUST be a level1 digest of 16-1 previous blocks, BUT there are only 9:
1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -414,14 +462,18 @@ mod tests {
#[test]
fn digest_iterator_returns_skewed_digest_blocks_skipping_level() {
fn test_with_zero(zero: u64) {
assert_eq!(digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1284)),
assert_eq!(
digest_build_iterator_blocks(16, 3, zero, zero + 4096, Some(zero + 1284)),
[
// level3 MUST point to previous 16-1 level2 digests, BUT there are only 5:
256, 512, 768, 1024, 1280,
// level3 MUST point to previous 16-1 level1 digests, BUT there are NO ANY L1-digests:
// level3 MUST be a level1 digest of 16-1 previous blocks, BUT there are only 3:
1281, 1282, 1283,
].iter().map(|item| zero + item).collect::<Vec<_>>(),
]
.iter()
.map(|item| zero + item)
.collect::<Vec<_>>(),
);
}
@@ -18,20 +18,22 @@
//! Functions + iterator that traverses changes tries and returns all
//! (block, extrinsic) pairs where given key has been changed.
use std::cell::RefCell;
use std::collections::VecDeque;
use codec::{Decode, Encode, Codec};
use crate::{
changes_trie::{
input::{ChildIndex, DigestIndex, DigestIndexValue, ExtrinsicIndex, ExtrinsicIndexValue},
storage::{InMemoryStorage, TrieBackendAdapter},
surface_iterator::{surface_iterator, SurfaceIterator},
AnchorBlockId, BlockNumber, ConfigurationRange, RootsStorage, Storage,
},
proving_backend::ProvingBackendRecorder,
trie_backend_essence::TrieBackendEssence,
};
use codec::{Codec, Decode, Encode};
use hash_db::Hasher;
use num_traits::Zero;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::Recorder;
use crate::changes_trie::{AnchorBlockId, ConfigurationRange, RootsStorage, Storage, BlockNumber};
use crate::changes_trie::input::{DigestIndex, ExtrinsicIndex, DigestIndexValue, ExtrinsicIndexValue};
use crate::changes_trie::storage::{TrieBackendAdapter, InMemoryStorage};
use crate::changes_trie::input::ChildIndex;
use crate::changes_trie::surface_iterator::{surface_iterator, SurfaceIterator};
use crate::proving_backend::ProvingBackendRecorder;
use crate::trie_backend_essence::{TrieBackendEssence};
use std::{cell::RefCell, collections::VecDeque};
/// Return changes of given key at given blocks range.
/// `max` is the number of best known block.
@@ -57,12 +59,7 @@ pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
@@ -72,7 +69,6 @@ pub fn key_changes<'a, H: Hasher, Number: BlockNumber>(
})
}
/// Returns proof of changes of given key at given blocks range.
/// `max` is the number of best known block.
pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
@@ -83,7 +79,10 @@ pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8],
) -> Result<Vec<Vec<u8>>, String> where H::Out: Codec {
) -> Result<Vec<Vec<u8>>, String>
where
H::Out: Codec,
{
// we can't query any roots before root
let max = std::cmp::min(max, end.number.clone());
@@ -96,12 +95,7 @@ pub fn key_changes_proof<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
@@ -130,8 +124,11 @@ pub fn key_changes_proof_check<'a, H: Hasher, Number: BlockNumber>(
end: &AnchorBlockId<H::Out, Number>,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
key: &[u8],
) -> Result<Vec<(Number, u32)>, String>
where
H::Out: Encode,
{
key_changes_proof_check_with_db(
config,
roots_storage,
@@ -153,8 +150,11 @@ pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
end: &AnchorBlockId<H::Out, Number>,
max: Number,
storage_key: Option<&PrefixedStorageKey>,
key: &[u8]
) -> Result<Vec<(Number, u32)>, String> where H::Out: Encode {
key: &[u8],
) -> Result<Vec<(Number, u32)>, String>
where
H::Out: Encode,
{
// we can't query any roots before root
let max = std::cmp::min(max, end.number.clone());
@@ -167,28 +167,24 @@ pub fn key_changes_proof_check_with_db<'a, H: Hasher, Number: BlockNumber>(
begin: begin.clone(),
end,
config: config.clone(),
surface: surface_iterator(
config,
max,
begin,
end.number.clone(),
)?,
surface: surface_iterator(config, max, begin, end.number.clone())?,
extrinsics: Default::default(),
blocks: Default::default(),
_hasher: ::std::marker::PhantomData::<H>::default(),
},
}.collect()
}
.collect()
}
/// Drilldown iterator - receives 'digest points' from surface iterator and explores
/// every point until extrinsic is found.
pub struct DrilldownIteratorEssence<'a, H, Number>
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
{
storage_key: Option<&'a PrefixedStorageKey>,
key: &'a [u8],
@@ -206,14 +202,14 @@ pub struct DrilldownIteratorEssence<'a, H, Number>
}
impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
where
H: Hasher,
Number: BlockNumber,
H::Out: 'a,
{
pub fn next<F>(&mut self, trie_reader: F) -> Option<Result<(Number, u32), String>>
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
{
match self.do_next(trie_reader) {
Ok(Some(res)) => Some(Ok(res)),
@@ -223,25 +219,26 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
}
fn do_next<F>(&mut self, mut trie_reader: F) -> Result<Option<(Number, u32)>, String>
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
where
F: FnMut(&dyn Storage<H, Number>, H::Out, &[u8]) -> Result<Option<Vec<u8>>, String>,
{
loop {
if let Some((block, extrinsic)) = self.extrinsics.pop_front() {
return Ok(Some((block, extrinsic)));
return Ok(Some((block, extrinsic)))
}
if let Some((block, level)) = self.blocks.pop_front() {
// not having a changes trie root is an error because:
// we never query roots for future blocks
// AND trie roots for old blocks are known (both on full + light node)
let trie_root = self.roots_storage.root(&self.end, block.clone())?
.ok_or_else(|| format!("Changes trie root for block {} is not found", block.clone()))?;
let trie_root =
self.roots_storage.root(&self.end, block.clone())?.ok_or_else(|| {
format!("Changes trie root for block {} is not found", block.clone())
})?;
let trie_root = if let Some(storage_key) = self.storage_key {
let child_key = ChildIndex {
block: block.clone(),
storage_key: storage_key.clone(),
}.encode();
let child_key =
ChildIndex { block: block.clone(), storage_key: storage_key.clone() }
.encode();
if let Some(trie_root) = trie_reader(self.storage, trie_root, &child_key)?
.and_then(|v| <Vec<u8>>::decode(&mut &v[..]).ok())
.map(|v| {
@@ -251,7 +248,7 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
}) {
trie_root
} else {
continue;
continue
}
} else {
trie_root
@@ -260,18 +257,24 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
// only return extrinsics for blocks before self.max
// most of blocks will be filtered out before pushing to `self.blocks`
// here we just throwing away changes at digest blocks we're processing
debug_assert!(block >= self.begin, "We shall not touch digests earlier than a range' begin");
debug_assert!(
block >= self.begin,
"We shall not touch digests earlier than a range' begin"
);
if block <= self.end.number {
let extrinsics_key = ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let extrinsics_key =
ExtrinsicIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let extrinsics = trie_reader(self.storage, trie_root, &extrinsics_key);
if let Some(extrinsics) = extrinsics? {
if let Ok(extrinsics) = ExtrinsicIndexValue::decode(&mut &extrinsics[..]) {
self.extrinsics.extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e)));
self.extrinsics
.extend(extrinsics.into_iter().rev().map(|e| (block.clone(), e)));
}
}
}
let blocks_key = DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let blocks_key =
DigestIndex { block: block.clone(), key: self.key.to_vec() }.encode();
let blocks = trie_reader(self.storage, trie_root, &blocks_key);
if let Some(blocks) = blocks? {
if let Ok(blocks) = <DigestIndexValue<Number>>::decode(&mut &blocks[..]) {
@@ -280,23 +283,35 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
let begin = self.begin.clone();
let end = self.end.number.clone();
let config = self.config.clone();
self.blocks.extend(blocks.into_iter()
.rev()
.filter(|b| level.map(|level| level > 1).unwrap_or(true) || (*b >= begin && *b <= end))
.map(|b| {
let prev_level = level
.map(|level| Some(level - 1))
.unwrap_or_else(||
Some(config.config.digest_level_at_block(config.zero.clone(), b.clone())
.map(|(level, _, _)| level)
.unwrap_or_else(|| Zero::zero())));
(b, prev_level)
})
self.blocks.extend(
blocks
.into_iter()
.rev()
.filter(|b| {
level.map(|level| level > 1).unwrap_or(true) ||
(*b >= begin && *b <= end)
})
.map(|b| {
let prev_level =
level.map(|level| Some(level - 1)).unwrap_or_else(|| {
Some(
config
.config
.digest_level_at_block(
config.zero.clone(),
b.clone(),
)
.map(|(level, _, _)| level)
.unwrap_or_else(|| Zero::zero()),
)
});
(b, prev_level)
}),
);
}
}
continue;
continue
}
match self.surface.next() {
@@ -310,46 +325,50 @@ impl<'a, H, Number> DrilldownIteratorEssence<'a, H, Number>
/// Exploring drilldown operator.
pub struct DrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
essence: DrilldownIteratorEssence<'a, H, Number>,
}
impl<'a, H: Hasher, Number: BlockNumber> Iterator for DrilldownIterator<'a, H, Number>
where H::Out: Encode
where
H::Out: Encode,
{
type Item = Result<(Number, u32), String>;
fn next(&mut self) -> Option<Self::Item> {
self.essence.next(|storage, root, key|
TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key))
self.essence.next(|storage, root, key| {
TrieBackendEssence::<_, H>::new(TrieBackendAdapter::new(storage), root).storage(key)
})
}
}
/// Proving drilldown iterator.
struct ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
essence: DrilldownIteratorEssence<'a, H, Number>,
proof_recorder: RefCell<Recorder<H::Out>>,
}
impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a,
{
/// Consume the iterator, extracting the gathered proof in lexicographical order
/// by value.
pub fn extract_proof(self) -> Vec<Vec<u8>> {
self.proof_recorder.into_inner().drain()
self.proof_recorder
.into_inner()
.drain()
.into_iter()
.map(|n| n.data.to_vec())
.collect()
@@ -357,32 +376,34 @@ impl<'a, H, Number> ProvingDrilldownIterator<'a, H, Number>
}
impl<'a, H, Number> Iterator for ProvingDrilldownIterator<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a + Codec,
where
Number: BlockNumber,
H: Hasher,
H::Out: 'a + Codec,
{
type Item = Result<(Number, u32), String>;
fn next(&mut self) -> Option<Self::Item> {
let proof_recorder = &mut *self.proof_recorder.try_borrow_mut()
let proof_recorder = &mut *self
.proof_recorder
.try_borrow_mut()
.expect("only fails when already borrowed; storage() is non-reentrant; qed");
self.essence.next(|storage, root, key|
self.essence.next(|storage, root, key| {
ProvingBackendRecorder::<_, H> {
backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root),
proof_recorder,
}.storage(key))
}
.storage(key)
})
}
}
#[cfg(test)]
mod tests {
use std::iter::FromIterator;
use crate::changes_trie::Configuration;
use crate::changes_trie::input::InputPair;
use crate::changes_trie::storage::InMemoryStorage;
use sp_runtime::traits::BlakeTwo256;
use super::*;
use crate::changes_trie::{input::InputPair, storage::InMemoryStorage, Configuration};
use sp_runtime::traits::BlakeTwo256;
use std::iter::FromIterator;
fn child_key() -> PrefixedStorageKey {
let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]);
@@ -391,64 +412,98 @@ mod tests {
fn prepare_for_drilldown() -> (Configuration, InMemoryStorage<BlakeTwo256, u64>) {
let config = Configuration { digest_interval: 4, digest_levels: 2 };
let backend = InMemoryStorage::with_inputs(vec![
// digest: 1..4 => [(3, 0)]
(1, vec![
]),
(2, vec![
]),
(3, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 3, key: vec![42] }, vec![0]),
]),
(4, vec![
InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3]),
]),
// digest: 5..8 => [(6, 3), (8, 1+2)]
(5, vec![]),
(6, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 6, key: vec![42] }, vec![3]),
]),
(7, vec![]),
(8, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 8, key: vec![42] }, vec![1, 2]),
InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]),
]),
// digest: 9..12 => []
(9, vec![]),
(10, vec![]),
(11, vec![]),
(12, vec![]),
// digest: 0..16 => [4, 8]
(13, vec![]),
(14, vec![]),
(15, vec![]),
(16, vec![
InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![4, 8]),
]),
], vec![(child_key(), vec![
(1, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 1, key: vec![42] }, vec![0]),
]),
(2, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 2, key: vec![42] }, vec![3]),
]),
(16, vec![
InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 16, key: vec![42] }, vec![5]),
InputPair::DigestIndex(DigestIndex { block: 16, key: vec![42] }, vec![2]),
]),
]),
]);
let backend = InMemoryStorage::with_inputs(
vec![
// digest: 1..4 => [(3, 0)]
(1, vec![]),
(2, vec![]),
(
3,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 3, key: vec![42] },
vec![0],
)],
),
(4, vec![InputPair::DigestIndex(DigestIndex { block: 4, key: vec![42] }, vec![3])]),
// digest: 5..8 => [(6, 3), (8, 1+2)]
(5, vec![]),
(
6,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 6, key: vec![42] },
vec![3],
)],
),
(7, vec![]),
(
8,
vec![
InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 8, key: vec![42] },
vec![1, 2],
),
InputPair::DigestIndex(DigestIndex { block: 8, key: vec![42] }, vec![6]),
],
),
// digest: 9..12 => []
(9, vec![]),
(10, vec![]),
(11, vec![]),
(12, vec![]),
// digest: 0..16 => [4, 8]
(13, vec![]),
(14, vec![]),
(15, vec![]),
(
16,
vec![InputPair::DigestIndex(
DigestIndex { block: 16, key: vec![42] },
vec![4, 8],
)],
),
],
vec![(
child_key(),
vec![
(
1,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 1, key: vec![42] },
vec![0],
)],
),
(
2,
vec![InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 2, key: vec![42] },
vec![3],
)],
),
(
16,
vec![
InputPair::ExtrinsicIndex(
ExtrinsicIndex { block: 16, key: vec![42] },
vec![5],
),
InputPair::DigestIndex(
DigestIndex { block: 16, key: vec![42] },
vec![2],
),
],
),
],
)],
);
(config, backend)
}
fn configuration_range<'a>(config: &'a Configuration, zero: u64) -> ConfigurationRange<'a, u64> {
ConfigurationRange {
config,
zero,
end: None,
}
fn configuration_range<'a>(
config: &'a Configuration,
zero: u64,
) -> ConfigurationRange<'a, u64> {
ConfigurationRange { config, zero, end: None }
}
#[test]
@@ -462,7 +517,8 @@ mod tests {
16,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -473,7 +529,8 @@ mod tests {
4,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -484,7 +541,8 @@ mod tests {
4,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -495,7 +553,8 @@ mod tests {
7,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(6, 3), (3, 0)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -506,7 +565,8 @@ mod tests {
8,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(8, 2), (8, 1)]));
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -517,7 +577,8 @@ mod tests {
8,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(6, 3)]));
}
@@ -534,7 +595,9 @@ mod tests {
1000,
None,
&[42],
).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
)
.and_then(|i| i.collect::<Result<Vec<_>, _>>())
.is_err());
assert!(key_changes::<BlakeTwo256, u64>(
configuration_range(&config, 0),
@@ -544,7 +607,9 @@ mod tests {
1000,
Some(&child_key()),
&[42],
).and_then(|i| i.collect::<Result<Vec<_>, _>>()).is_err());
)
.and_then(|i| i.collect::<Result<Vec<_>, _>>())
.is_err());
}
#[test]
@@ -558,7 +623,8 @@ mod tests {
50,
None,
&[42],
).is_err());
)
.is_err());
assert!(key_changes::<BlakeTwo256, u64>(
configuration_range(&config, 0),
&storage,
@@ -567,10 +633,10 @@ mod tests {
100,
None,
&[42],
).is_err());
)
.is_err());
}
#[test]
fn proving_drilldown_iterator_works() {
// happens on remote full node:
@@ -578,13 +644,27 @@ mod tests {
// create drilldown iterator that records all trie nodes during drilldown
let (remote_config, remote_storage) = prepare_for_drilldown();
let remote_proof = key_changes_proof::<BlakeTwo256, u64>(
configuration_range(&remote_config, 0), &remote_storage, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]).unwrap();
configuration_range(&remote_config, 0),
&remote_storage,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
None,
&[42],
)
.unwrap();
let (remote_config, remote_storage) = prepare_for_drilldown();
let remote_proof_child = key_changes_proof::<BlakeTwo256, u64>(
configuration_range(&remote_config, 0), &remote_storage, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]).unwrap();
configuration_range(&remote_config, 0),
&remote_storage,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
Some(&child_key()),
&[42],
)
.unwrap();
// happens on local light node:
@@ -592,14 +672,28 @@ mod tests {
let (local_config, local_storage) = prepare_for_drilldown();
local_storage.clear_storage();
let local_result = key_changes_proof_check::<BlakeTwo256, u64>(
configuration_range(&local_config, 0), &local_storage, remote_proof, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, None, &[42]);
configuration_range(&local_config, 0),
&local_storage,
remote_proof,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
None,
&[42],
);
let (local_config, local_storage) = prepare_for_drilldown();
local_storage.clear_storage();
let local_result_child = key_changes_proof_check::<BlakeTwo256, u64>(
configuration_range(&local_config, 0), &local_storage, remote_proof_child, 1,
&AnchorBlockId { hash: Default::default(), number: 16 }, 16, Some(&child_key()), &[42]);
configuration_range(&local_config, 0),
&local_storage,
remote_proof_child,
1,
&AnchorBlockId { hash: Default::default(), number: 16 },
16,
Some(&child_key()),
&[42],
);
// check that drilldown result is the same as if it was happening at the full node
assert_eq!(local_result, Ok(vec![(8, 2), (8, 1), (6, 3), (3, 0)]));
@@ -620,12 +714,22 @@ mod tests {
// regular blocks: 89, 90, 91
let mut input = (1u64..92u64).map(|b| (b, vec![])).collect::<Vec<_>>();
// changed at block#63 and covered by L3 digest at block#64
input[63 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0]));
input[64 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63]));
input[63 - 1]
.1
.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 63, key: vec![42] }, vec![0]));
input[64 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 64, key: vec![42] }, vec![63]));
// changed at block#79 and covered by L2 digest at block#80 + skewed digest at block#91
input[79 - 1].1.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1]));
input[80 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79]));
input[91 - 1].1.push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80]));
input[79 - 1]
.1
.push(InputPair::ExtrinsicIndex(ExtrinsicIndex { block: 79, key: vec![42] }, vec![1]));
input[80 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 80, key: vec![42] }, vec![79]));
input[91 - 1]
.1
.push(InputPair::DigestIndex(DigestIndex { block: 91, key: vec![42] }, vec![80]));
let storage = InMemoryStorage::with_inputs(input, vec![]);
let drilldown_result = key_changes::<BlakeTwo256, u64>(
@@ -636,7 +740,8 @@ mod tests {
100_000u64,
None,
&[42],
).and_then(Result::from_iter);
)
.and_then(Result::from_iter);
assert_eq!(drilldown_result, Ok(vec![(79, 1), (63, 0)]));
}
}
@@ -17,11 +17,8 @@
//! Different types of changes trie input pairs.
use codec::{Decode, Encode, Input, Output, Error};
use crate::{
StorageKey, StorageValue,
changes_trie::BlockNumber
};
use crate::{changes_trie::BlockNumber, StorageKey, StorageValue};
use codec::{Decode, Encode, Error, Input, Output};
use sp_core::storage::PrefixedStorageKey;
/// Key of { changed key => set of extrinsic indices } mapping.
@@ -140,7 +137,6 @@ impl<Number: BlockNumber> DigestIndex<Number> {
}
}
impl<Number: BlockNumber> Encode for DigestIndex<Number> {
fn encode_to<W: Output + ?Sized>(&self, dest: &mut W) {
dest.push_byte(2);
@@ -58,63 +58,86 @@ mod prune;
mod storage;
mod surface_iterator;
pub use self::build_cache::{BuildCache, CachedBuildData, CacheAction};
pub use self::storage::InMemoryStorage;
pub use self::changes_iterator::{
key_changes, key_changes_proof,
key_changes_proof_check, key_changes_proof_check_with_db,
pub use self::{
build_cache::{BuildCache, CacheAction, CachedBuildData},
changes_iterator::{
key_changes, key_changes_proof, key_changes_proof_check, key_changes_proof_check_with_db,
},
prune::prune,
storage::InMemoryStorage,
};
pub use self::prune::prune;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use hash_db::{Hasher, Prefix};
use num_traits::{One, Zero};
use codec::{Decode, Encode};
use sp_core;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::{MemoryDB, DBValue, TrieMut};
use sp_trie::trie_types::TrieDBMut;
use crate::{
StorageKey,
backend::Backend,
overlayed_changes::OverlayedChanges,
changes_trie::{
build::prepare_input,
build_cache::{IncompleteCachedBuildData, IncompleteCacheAction},
build_cache::{IncompleteCacheAction, IncompleteCachedBuildData},
},
overlayed_changes::OverlayedChanges,
StorageKey,
};
use codec::{Decode, Encode};
use hash_db::{Hasher, Prefix};
use num_traits::{One, Zero};
use sp_core::{self, storage::PrefixedStorageKey};
use sp_trie::{trie_types::TrieDBMut, DBValue, MemoryDB, TrieMut};
use std::{
collections::{HashMap, HashSet},
convert::TryInto,
};
/// Requirements for block number that can be used with changes tries.
pub trait BlockNumber:
Send + Sync + 'static +
std::fmt::Display +
Clone +
From<u32> + TryInto<u32> + One + Zero +
PartialEq + Ord +
std::hash::Hash +
std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
std::ops::Rem<Self, Output=Self> +
std::ops::AddAssign<Self> +
num_traits::CheckedMul + num_traits::CheckedSub +
Decode + Encode
{}
Send
+ Sync
+ 'static
+ std::fmt::Display
+ Clone
+ From<u32>
+ TryInto<u32>
+ One
+ Zero
+ PartialEq
+ Ord
+ std::hash::Hash
+ std::ops::Add<Self, Output = Self>
+ ::std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ ::std::ops::Div<Self, Output = Self>
+ std::ops::Rem<Self, Output = Self>
+ std::ops::AddAssign<Self>
+ num_traits::CheckedMul
+ num_traits::CheckedSub
+ Decode
+ Encode
{
}
impl<T> BlockNumber for T where T:
Send + Sync + 'static +
std::fmt::Display +
Clone +
From<u32> + TryInto<u32> + One + Zero +
PartialEq + Ord +
std::hash::Hash +
std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
std::ops::Rem<Self, Output=Self> +
std::ops::AddAssign<Self> +
num_traits::CheckedMul + num_traits::CheckedSub +
Decode + Encode,
{}
impl<T> BlockNumber for T where
T: Send
+ Sync
+ 'static
+ std::fmt::Display
+ Clone
+ From<u32>
+ TryInto<u32>
+ One
+ Zero
+ PartialEq
+ Ord
+ std::hash::Hash
+ std::ops::Add<Self, Output = Self>
+ ::std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ ::std::ops::Div<Self, Output = Self>
+ std::ops::Rem<Self, Output = Self>
+ std::ops::AddAssign<Self>
+ num_traits::CheckedMul
+ num_traits::CheckedSub
+ Decode
+ Encode
{
}
/// Block identifier that could be used to determine fork of this block.
#[derive(Debug)]
@@ -143,7 +166,11 @@ pub trait RootsStorage<H: Hasher, Number: BlockNumber>: Send + Sync {
fn build_anchor(&self, hash: H::Out) -> Result<AnchorBlockId<H::Out, Number>, String>;
/// Get changes trie root for the block with given number which is an ancestor (or the block
/// itself) of the anchor_block (i.e. anchor_block.number >= block).
fn root(&self, anchor: &AnchorBlockId<H::Out, Number>, block: Number) -> Result<Option<H::Out>, String>;
fn root(
&self,
anchor: &AnchorBlockId<H::Out, Number>,
block: Number,
) -> Result<Option<H::Out>, String>;
}
/// Changes trie storage. Provides access to trie roots and trie nodes.
@@ -162,9 +189,13 @@ pub trait Storage<H: Hasher, Number: BlockNumber>: RootsStorage<H, Number> {
}
/// Changes trie storage -> trie backend essence adapter.
pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>(pub &'a dyn Storage<H, Number>);
pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>(
pub &'a dyn Storage<H, Number>,
);
impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage<H> for TrieBackendStorageAdapter<'a, H, N> {
impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage<H>
for TrieBackendStorageAdapter<'a, H, N>
{
type Overlay = sp_trie::MemoryDB<H>;
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String> {
@@ -188,26 +219,14 @@ pub struct ConfigurationRange<'a, N> {
impl<'a, H, Number> State<'a, H, Number> {
/// Create state with given config and storage.
pub fn new(
config: Configuration,
zero: Number,
storage: &'a dyn Storage<H, Number>,
) -> Self {
Self {
config,
zero,
storage,
}
pub fn new(config: Configuration, zero: Number, storage: &'a dyn Storage<H, Number>) -> Self {
Self { config, zero, storage }
}
}
impl<'a, H, Number: Clone> Clone for State<'a, H, Number> {
fn clone(&self) -> Self {
State {
config: self.config.clone(),
zero: self.zero.clone(),
storage: self.storage,
}
State { config: self.config.clone(), zero: self.zero.clone(), storage: self.storage }
}
}
@@ -227,20 +246,24 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
parent_hash: H::Out,
panic_on_storage_error: bool,
) -> Result<Option<(MemoryDB<H>, H::Out, CacheAction<H::Out, Number>)>, ()>
where
H::Out: Ord + 'static + Encode,
where
H::Out: Ord + 'static + Encode,
{
/// Panics when `res.is_err() && panic`, otherwise it returns `Err(())` on an error.
fn maybe_panic<R, E: std::fmt::Debug>(
res: std::result::Result<R, E>,
panic: bool,
) -> std::result::Result<R, ()> {
res.map(Ok)
.unwrap_or_else(|e| if panic {
panic!("changes trie: storage access is not allowed to fail within runtime: {:?}", e)
res.map(Ok).unwrap_or_else(|e| {
if panic {
panic!(
"changes trie: storage access is not allowed to fail within runtime: {:?}",
e
)
} else {
Err(())
})
}
})
}
// when storage isn't provided, changes tries aren't created
@@ -255,11 +278,12 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
// prepare configuration range - we already know zero block. Current block may be the end block if configuration
// has been changed in this block
let is_config_changed = match changes.storage(sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) {
Some(Some(new_config)) => new_config != &state.config.encode()[..],
Some(None) => true,
None => false,
};
let is_config_changed =
match changes.storage(sp_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) {
Some(Some(new_config)) => new_config != &state.config.encode()[..],
Some(None) => true,
None => false,
};
let config_range = ConfigurationRange {
config: &state.config,
zero: state.zero.clone(),
@@ -303,10 +327,8 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
}
cache_action = cache_action.insert(
Some(child_index.storage_key.clone()),
storage_changed_keys,
);
cache_action =
cache_action.insert(Some(child_index.storage_key.clone()), storage_changed_keys);
}
if not_empty {
child_roots.push(input::InputPair::ChildIndex(child_index, root.as_ref().to_vec()));
@@ -331,10 +353,7 @@ pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
}
cache_action = cache_action.insert(
None,
storage_changed_keys,
);
cache_action = cache_action.insert(None, storage_changed_keys);
}
let cache_action = cache_action.complete(block, &root);
@@ -350,20 +369,21 @@ fn prepare_cached_build_data<Number: BlockNumber>(
// because it'll never be used again for building other tries
// => let's clear the cache
if !config.config.is_digest_build_enabled() {
return IncompleteCacheAction::Clear;
return IncompleteCacheAction::Clear
}
// when this is the last block where current configuration is active
// => let's clear the cache
if config.end.as_ref() == Some(&block) {
return IncompleteCacheAction::Clear;
return IncompleteCacheAction::Clear
}
// we do not need to cache anything when top-level digest trie is created, because
// it'll never be used again for building other tries
// => let's clear the cache
match config.config.digest_level_at_block(config.zero.clone(), block) {
Some((digest_level, _, _)) if digest_level == config.config.digest_levels => IncompleteCacheAction::Clear,
Some((digest_level, _, _)) if digest_level == config.config.digest_levels =>
IncompleteCacheAction::Clear,
_ => IncompleteCacheAction::CacheBuildData(IncompleteCachedBuildData::new()),
}
}
@@ -399,6 +419,9 @@ mod tests {
fn cache_is_cleared_when_end_block_of_configuration_is_built() {
let config = Configuration { digest_interval: 8, digest_levels: 2 };
let config_range = ConfigurationRange { zero: 0, end: Some(4u32), config: &config };
assert_eq!(prepare_cached_build_data(config_range.clone(), 4u32), IncompleteCacheAction::Clear);
assert_eq!(
prepare_cached_build_data(config_range.clone(), 4u32),
IncompleteCacheAction::Clear
);
}
}
@@ -17,16 +17,20 @@
//! Changes trie pruning-related functions.
use crate::{
changes_trie::{
input::{ChildIndex, InputKey},
storage::TrieBackendAdapter,
AnchorBlockId, BlockNumber, Storage,
},
proving_backend::ProvingBackendRecorder,
trie_backend_essence::TrieBackendEssence,
};
use codec::{Codec, Decode};
use hash_db::Hasher;
use sp_trie::Recorder;
use log::warn;
use num_traits::One;
use crate::proving_backend::ProvingBackendRecorder;
use crate::trie_backend_essence::TrieBackendEssence;
use crate::changes_trie::{AnchorBlockId, Storage, BlockNumber};
use crate::changes_trie::storage::TrieBackendAdapter;
use crate::changes_trie::input::{ChildIndex, InputKey};
use codec::{Decode, Codec};
use sp_trie::Recorder;
/// Prune obsolete changes tries. Pruning happens at the same block, where highest
/// level digest is created. Pruning guarantees to save changes tries for last
@@ -38,12 +42,14 @@ pub fn prune<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
last: Number,
current_block: &AnchorBlockId<H::Out, Number>,
mut remove_trie_node: F,
) where H::Out: Codec {
) where
H::Out: Codec,
{
// delete changes trie for every block in range
let mut block = first;
loop {
if block >= last.clone() + One::one() {
break;
break
}
let prev_block = block.clone();
@@ -56,7 +62,7 @@ pub fn prune<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
Err(error) => {
// try to delete other tries
warn!(target: "trie", "Failed to read changes trie root from DB: {}", error);
continue;
continue
},
};
let children_roots = {
@@ -91,8 +97,9 @@ fn prune_trie<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
storage: &dyn Storage<H, Number>,
root: H::Out,
remove_trie_node: &mut F,
) where H::Out: Codec {
) where
H::Out: Codec,
{
// enumerate all changes trie' keys, recording all nodes that have been 'touched'
// (effectively - all changes trie nodes)
let mut proof_recorder: Recorder<H::Out> = Default::default();
@@ -113,14 +120,13 @@ fn prune_trie<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use sp_trie::MemoryDB;
use sp_core::H256;
use crate::backend::insert_into_memory_db;
use crate::changes_trie::storage::InMemoryStorage;
use codec::Encode;
use sp_runtime::traits::BlakeTwo256;
use super::*;
use crate::{backend::insert_into_memory_db, changes_trie::storage::InMemoryStorage};
use codec::Encode;
use sp_core::H256;
use sp_runtime::traits::BlakeTwo256;
use sp_trie::MemoryDB;
use std::collections::HashSet;
fn prune_by_collect(
storage: &dyn Storage<BlakeTwo256, u64>,
@@ -130,8 +136,9 @@ mod tests {
) -> HashSet<H256> {
let mut pruned_trie_nodes = HashSet::new();
let anchor = AnchorBlockId { hash: Default::default(), number: current_block };
prune(storage, first, last, &anchor,
|node| { pruned_trie_nodes.insert(node); });
prune(storage, first, last, &anchor, |node| {
pruned_trie_nodes.insert(node);
});
pruned_trie_nodes
}
@@ -139,28 +146,36 @@ mod tests {
fn prune_works() {
fn prepare_storage() -> InMemoryStorage<BlakeTwo256, u64> {
let child_info = sp_core::storage::ChildInfo::new_default(&b"1"[..]);
let child_key = ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() }.encode();
let child_key =
ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() }
.encode();
let mut mdb1 = MemoryDB::<BlakeTwo256>::default();
let root1 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb1, vec![(vec![10], vec![20])]).unwrap();
let root1 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb1, vec![(vec![10], vec![20])])
.unwrap();
let mut mdb2 = MemoryDB::<BlakeTwo256>::default();
let root2 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb2,
vec![(vec![11], vec![21]), (vec![12], vec![22])],
).unwrap();
)
.unwrap();
let mut mdb3 = MemoryDB::<BlakeTwo256>::default();
let ch_root3 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb3, vec![(vec![110], vec![120])]).unwrap();
let root3 = insert_into_memory_db::<BlakeTwo256, _>(&mut mdb3, vec![
(vec![13], vec![23]),
(vec![14], vec![24]),
(child_key, ch_root3.as_ref().encode()),
]).unwrap();
let ch_root3 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb3, vec![(vec![110], vec![120])])
.unwrap();
let root3 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb3,
vec![
(vec![13], vec![23]),
(vec![14], vec![24]),
(child_key, ch_root3.as_ref().encode()),
],
)
.unwrap();
let mut mdb4 = MemoryDB::<BlakeTwo256>::default();
let root4 = insert_into_memory_db::<BlakeTwo256, _>(
&mut mdb4,
vec![(vec![15], vec![25])],
).unwrap();
let root4 =
insert_into_memory_db::<BlakeTwo256, _>(&mut mdb4, vec![(vec![15], vec![25])])
.unwrap();
let storage = InMemoryStorage::new();
storage.insert(65, root1, mdb1);
storage.insert(66, root2, mdb2);
@@ -17,22 +17,21 @@
//! Changes trie storage utilities.
use std::collections::{BTreeMap, HashSet, HashMap};
use hash_db::{Hasher, Prefix, EMPTY_PREFIX};
use sp_core::storage::PrefixedStorageKey;
use sp_trie::DBValue;
use sp_trie::MemoryDB;
use parking_lot::RwLock;
use crate::{
StorageKey,
changes_trie::{AnchorBlockId, BlockNumber, BuildCache, RootsStorage, Storage},
trie_backend_essence::TrieBackendStorage,
changes_trie::{BuildCache, RootsStorage, Storage, AnchorBlockId, BlockNumber},
StorageKey,
};
use hash_db::{Hasher, Prefix, EMPTY_PREFIX};
use parking_lot::RwLock;
use sp_core::storage::PrefixedStorageKey;
use sp_trie::{DBValue, MemoryDB};
use std::collections::{BTreeMap, HashMap, HashSet};
#[cfg(test)]
use crate::backend::insert_into_memory_db;
#[cfg(test)]
use crate::changes_trie::input::{InputPair, ChildIndex};
use crate::changes_trie::input::{ChildIndex, InputPair};
/// In-memory implementation of changes trie storage.
pub struct InMemoryStorage<H: Hasher, Number: BlockNumber> {
@@ -55,10 +54,7 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
/// Creates storage from given in-memory database.
pub fn with_db(mdb: MemoryDB<H>) -> Self {
Self {
data: RwLock::new(InMemoryStorageData {
roots: BTreeMap::new(),
mdb,
}),
data: RwLock::new(InMemoryStorageData { roots: BTreeMap::new(), mdb }),
cache: BuildCache::new(),
}
}
@@ -72,7 +68,7 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
pub fn with_proof(proof: Vec<Vec<u8>>) -> Self {
use hash_db::HashDB;
let mut proof_db = MemoryDB::<H>::default();
let mut proof_db = MemoryDB::<H>::default();
for item in proof {
proof_db.insert(EMPTY_PREFIX, &item);
}
@@ -104,7 +100,8 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
let mut roots = BTreeMap::new();
for (storage_key, child_input) in children_inputs {
for (block, pairs) in child_input {
let root = insert_into_memory_db::<H, _>(&mut mdb, pairs.into_iter().map(Into::into));
let root =
insert_into_memory_db::<H, _>(&mut mdb, pairs.into_iter().map(Into::into));
if let Some(root) = root {
let ix = if let Some(ix) = top_inputs.iter().position(|v| v.0 == block) {
@@ -129,17 +126,14 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
}
InMemoryStorage {
data: RwLock::new(InMemoryStorageData {
roots,
mdb,
}),
data: RwLock::new(InMemoryStorageData { roots, mdb }),
cache: BuildCache::new(),
}
}
#[cfg(test)]
pub fn clear_storage(&self) {
self.data.write().mdb = MemoryDB::default(); // use new to be more correct
self.data.write().mdb = MemoryDB::default(); // use new to be more correct
}
#[cfg(test)]
@@ -165,13 +159,20 @@ impl<H: Hasher, Number: BlockNumber> InMemoryStorage<H, Number> {
impl<H: Hasher, Number: BlockNumber> RootsStorage<H, Number> for InMemoryStorage<H, Number> {
fn build_anchor(&self, parent_hash: H::Out) -> Result<AnchorBlockId<H::Out, Number>, String> {
self.data.read().roots.iter()
self.data
.read()
.roots
.iter()
.find(|(_, v)| **v == parent_hash)
.map(|(k, _)| AnchorBlockId { hash: parent_hash, number: k.clone() })
.ok_or_else(|| format!("Can't find associated number for block {:?}", parent_hash))
}
fn root(&self, _anchor_block: &AnchorBlockId<H::Out, Number>, block: Number) -> Result<Option<H::Out>, String> {
fn root(
&self,
_anchor_block: &AnchorBlockId<H::Out, Number>,
block: Number,
) -> Result<Option<H::Out>, String> {
Ok(self.data.read().roots.get(&block).cloned())
}
}
@@ -201,9 +202,9 @@ impl<'a, H: Hasher, Number: BlockNumber> TrieBackendAdapter<'a, H, Number> {
}
impl<'a, H, Number> TrieBackendStorage<H> for TrieBackendAdapter<'a, H, Number>
where
Number: BlockNumber,
H: Hasher,
where
Number: BlockNumber,
H: Hasher,
{
type Overlay = MemoryDB<H>;
@@ -21,8 +21,8 @@
//! of points at the terrain (mountains and valleys) inside this range that have to be drilled down to
//! search for gems.
use crate::changes_trie::{BlockNumber, ConfigurationRange};
use num_traits::One;
use crate::changes_trie::{ConfigurationRange, BlockNumber};
/// Returns surface iterator for given range of blocks.
///
@@ -34,12 +34,8 @@ pub fn surface_iterator<'a, Number: BlockNumber>(
begin: Number,
end: Number,
) -> Result<SurfaceIterator<'a, Number>, String> {
let (current, current_begin, digest_step, digest_level) = lower_bound_max_digest(
config.clone(),
max.clone(),
begin.clone(),
end,
)?;
let (current, current_begin, digest_step, digest_level) =
lower_bound_max_digest(config.clone(), max.clone(), begin.clone(), end)?;
Ok(SurfaceIterator {
config,
begin,
@@ -89,7 +85,8 @@ impl<'a, Number: BlockNumber> Iterator for SurfaceIterator<'a, Number> {
self.begin.clone(),
next,
);
let (current, current_begin, digest_step, digest_level) = match max_digest_interval {
let (current, current_begin, digest_step, digest_level) = match max_digest_interval
{
Err(err) => return Some(Err(err)),
Ok(range) => range,
};
@@ -114,14 +111,21 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
end: Number,
) -> Result<(Number, Number, u32, Option<u32>), String> {
if end > max || begin > end {
return Err(format!("invalid changes range: {}..{}/{}", begin, end, max));
return Err(format!("invalid changes range: {}..{}/{}", begin, end, max))
}
if begin <= config.zero || config.end.as_ref().map(|config_end| end > *config_end).unwrap_or(false) {
return Err(format!("changes trie range is not covered by configuration: {}..{}/{}..{}",
begin, end, config.zero, match config.end.as_ref() {
if begin <= config.zero ||
config.end.as_ref().map(|config_end| end > *config_end).unwrap_or(false)
{
return Err(format!(
"changes trie range is not covered by configuration: {}..{}/{}..{}",
begin,
end,
config.zero,
match config.end.as_ref() {
Some(config_end) => format!("{}", config_end),
None => "None".into(),
}));
}
))
}
let mut digest_level = 0u32;
@@ -135,10 +139,16 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
let new_digest_level = digest_level + 1;
let new_digest_step = digest_step * config.config.digest_interval;
let new_digest_interval = config.config.digest_interval * {
if digest_interval == 0 { 1 } else { digest_interval }
if digest_interval == 0 {
1
} else {
digest_interval
}
};
let new_digest_begin = config.zero.clone() + ((current.clone() - One::one() - config.zero.clone())
/ new_digest_interval.into()) * new_digest_interval.into();
let new_digest_begin = config.zero.clone() +
((current.clone() - One::one() - config.zero.clone()) /
new_digest_interval.into()) *
new_digest_interval.into();
let new_digest_end = new_digest_begin.clone() + new_digest_interval.into();
let new_current = new_digest_begin.clone() + new_digest_interval.into();
@@ -150,16 +160,20 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
skewed_digest_end.clone(),
);
if let Some(skewed_digest_start) = skewed_digest_start {
let skewed_digest_range = (skewed_digest_end.clone() - skewed_digest_start.clone())
.try_into().ok()
.expect("skewed digest range is always <= max level digest range;\
max level digest range always fits u32; qed");
let skewed_digest_range = (skewed_digest_end.clone() -
skewed_digest_start.clone())
.try_into()
.ok()
.expect(
"skewed digest range is always <= max level digest range;\
max level digest range always fits u32; qed",
);
return Ok((
skewed_digest_end.clone(),
skewed_digest_start,
skewed_digest_range,
None,
));
))
}
}
}
@@ -169,7 +183,7 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
if begin < new_digest_begin {
current_begin = new_digest_begin;
}
break;
break
}
// we can (and will) use this digest
@@ -181,30 +195,24 @@ fn lower_bound_max_digest<'a, Number: BlockNumber>(
// if current digest covers the whole range => no need to use next level digest
if current_begin <= begin && new_digest_end >= end {
break;
break
}
}
}
Ok((
current,
current_begin,
digest_step,
Some(digest_level),
))
Ok((current, current_begin, digest_step, Some(digest_level)))
}
#[cfg(test)]
mod tests {
use crate::changes_trie::{Configuration};
use super::*;
use crate::changes_trie::Configuration;
fn configuration_range<'a>(config: &'a Configuration, zero: u64) -> ConfigurationRange<'a, u64> {
ConfigurationRange {
config,
zero,
end: None,
}
fn configuration_range<'a>(
config: &'a Configuration,
zero: u64,
) -> ConfigurationRange<'a, u64> {
ConfigurationRange { config, zero, end: None }
}
#[test]
@@ -213,13 +221,15 @@ mod tests {
// when config activates at 0
assert_eq!(
lower_bound_max_digest(configuration_range(&config, 0u64), 100_000u64, 20u64, 180u64).unwrap(),
lower_bound_max_digest(configuration_range(&config, 0u64), 100_000u64, 20u64, 180u64)
.unwrap(),
(192, 176, 16, Some(2)),
);
// when config activates at 30
assert_eq!(
lower_bound_max_digest(configuration_range(&config, 30u64), 100_000u64, 50u64, 210u64).unwrap(),
lower_bound_max_digest(configuration_range(&config, 30u64), 100_000u64, 50u64, 210u64)
.unwrap(),
(222, 206, 16, Some(2)),
);
}
@@ -230,40 +240,61 @@ mod tests {
// when config activates at 0
assert_eq!(
surface_iterator(
configuration_range(&config, 0u64),
100_000u64,
40u64,
180u64,
).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 0u64), 100_000u64, 40u64, 180u64,)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((192, Some(2))), Ok((176, Some(2))), Ok((160, Some(2))), Ok((144, Some(2))),
Ok((128, Some(2))), Ok((112, Some(2))), Ok((96, Some(2))), Ok((80, Some(2))),
Ok((64, Some(2))), Ok((48, Some(2))),
Ok((192, Some(2))),
Ok((176, Some(2))),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
// when config activates at 30
assert_eq!(
surface_iterator(
configuration_range(&config, 30u64),
100_000u64,
40u64,
180u64,
).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 30u64), 100_000u64, 40u64, 180u64,)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((190, Some(2))), Ok((174, Some(2))), Ok((158, Some(2))), Ok((142, Some(2))), Ok((126, Some(2))),
Ok((110, Some(2))), Ok((94, Some(2))), Ok((78, Some(2))), Ok((62, Some(2))), Ok((46, Some(2))),
Ok((190, Some(2))),
Ok((174, Some(2))),
Ok((158, Some(2))),
Ok((142, Some(2))),
Ok((126, Some(2))),
Ok((110, Some(2))),
Ok((94, Some(2))),
Ok((78, Some(2))),
Ok((62, Some(2))),
Ok((46, Some(2))),
],
);
// when config activates at 0 AND max block is before next digest
assert_eq!(
surface_iterator(configuration_range(&config, 0u64), 183u64, 40u64, 183u64).unwrap().collect::<Vec<_>>(),
surface_iterator(configuration_range(&config, 0u64), 183u64, 40u64, 183u64)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((183, Some(0))), Ok((182, Some(0))), Ok((181, Some(0))), Ok((180, Some(1))),
Ok((176, Some(2))), Ok((160, Some(2))), Ok((144, Some(2))), Ok((128, Some(2))), Ok((112, Some(2))),
Ok((96, Some(2))), Ok((80, Some(2))), Ok((64, Some(2))), Ok((48, Some(2))),
Ok((183, Some(0))),
Ok((182, Some(0))),
Ok((181, Some(0))),
Ok((180, Some(1))),
Ok((176, Some(2))),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
}
@@ -276,10 +307,19 @@ mod tests {
// when config activates at 0 AND ends at 170
config_range.end = Some(170);
assert_eq!(
surface_iterator(config_range, 100_000u64, 40u64, 170u64).unwrap().collect::<Vec<_>>(),
surface_iterator(config_range, 100_000u64, 40u64, 170u64)
.unwrap()
.collect::<Vec<_>>(),
vec![
Ok((170, None)), Ok((160, Some(2))), Ok((144, Some(2))), Ok((128, Some(2))), Ok((112, Some(2))),
Ok((96, Some(2))), Ok((80, Some(2))), Ok((64, Some(2))), Ok((48, Some(2))),
Ok((170, None)),
Ok((160, Some(2))),
Ok((144, Some(2))),
Ok((128, Some(2))),
Ok((112, Some(2))),
Ok((96, Some(2))),
Ok((80, Some(2))),
Ok((64, Some(2))),
Ok((48, Some(2))),
],
);
}
@@ -16,7 +16,6 @@
// limitations under the License.
/// State Machine Errors
use sp_std::fmt;
/// State Machine Error bound.
+142 -168
View File
@@ -18,25 +18,28 @@
//! Concrete externalities implementation.
use crate::{
StorageKey, StorageValue, OverlayedChanges, IndexOperation,
backend::Backend, overlayed_changes::OverlayedExtensions,
};
use hash_db::Hasher;
use sp_core::{
storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey},
hexdisplay::HexDisplay,
};
use sp_trie::{trie_types::Layout, empty_child_trie_root};
use sp_externalities::{
Externalities, Extensions, Extension, ExtensionStore,
backend::Backend, overlayed_changes::OverlayedExtensions, IndexOperation, OverlayedChanges,
StorageKey, StorageValue,
};
use codec::{Decode, Encode, EncodeAppend};
use hash_db::Hasher;
use sp_core::{
hexdisplay::HexDisplay,
storage::{well_known_keys::is_child_storage_key, ChildInfo, TrackedStorageKey},
};
use sp_externalities::{Extension, ExtensionStore, Extensions, Externalities};
use sp_trie::{empty_child_trie_root, trie_types::Layout};
use sp_std::{fmt, any::{Any, TypeId}, vec::Vec, vec, boxed::Box, cmp::Ordering};
use crate::{warn, trace, log_error};
#[cfg(feature = "std")]
use crate::changes_trie::State as ChangesTrieState;
use crate::StorageTransactionCache;
use crate::{log_error, trace, warn, StorageTransactionCache};
use sp_std::{
any::{Any, TypeId},
boxed::Box,
cmp::Ordering,
fmt, vec,
vec::Vec,
};
#[cfg(feature = "std")]
use std::error;
@@ -46,7 +49,6 @@ 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()
@@ -91,10 +93,10 @@ impl<B: error::Error, E: error::Error> error::Error for Error<B, E> {
/// Wraps a read-only backend, call executor, and current overlayed changes.
pub struct Ext<'a, H, N, B>
where
H: Hasher,
B: 'a + Backend<H>,
N: crate::changes_trie::BlockNumber,
where
H: Hasher,
B: 'a + Backend<H>,
N: crate::changes_trie::BlockNumber,
{
/// The overlayed changes to write to.
overlay: &'a mut OverlayedChanges,
@@ -114,12 +116,11 @@ pub struct Ext<'a, H, N, B>
extensions: Option<OverlayedExtensions<'a>>,
}
impl<'a, H, N, B> Ext<'a, H, N, B>
where
H: Hasher,
B: Backend<H>,
N: crate::changes_trie::BlockNumber,
where
H: Hasher,
B: Backend<H>,
N: crate::changes_trie::BlockNumber,
{
/// Create a new `Ext`.
#[cfg(not(feature = "std"))]
@@ -128,13 +129,7 @@ impl<'a, H, N, B> Ext<'a, H, N, B>
storage_transaction_cache: &'a mut StorageTransactionCache<B::Transaction, H, N>,
backend: &'a B,
) -> Self {
Ext {
overlay,
backend,
id: 0,
storage_transaction_cache,
_phantom: Default::default(),
}
Ext { overlay, backend, id: 0, storage_transaction_cache, _phantom: Default::default() }
}
/// Create a new `Ext` from overlayed changes and read-only backend
@@ -176,7 +171,9 @@ where
pub fn storage_pairs(&self) -> Vec<(StorageKey, StorageValue)> {
use std::collections::HashMap;
self.backend.pairs().iter()
self.backend
.pairs()
.iter()
.map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec())))
.chain(self.overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned())))
.collect::<HashMap<_, _>>()
@@ -199,8 +196,11 @@ where
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
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));
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));
// NOTE: be careful about touching the key names used outside substrate!
trace!(
@@ -222,7 +222,8 @@ where
fn storage_hash(&self, key: &[u8]) -> Option<Vec<u8>> {
let _guard = guard();
let result = self.overlay
let result = self
.overlay
.storage(key)
.map(|x| x.map(|x| H::hash(x)))
.unwrap_or_else(|| self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL));
@@ -235,19 +236,15 @@ where
result.map(|r| r.encode())
}
fn child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageValue> {
fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageValue> {
let _guard = guard();
let result = self.overlay
let result = self
.overlay
.child_storage(child_info, key)
.map(|x| x.map(|x| x.to_vec()))
.unwrap_or_else(||
self.backend.child_storage(child_info, key)
.expect(EXT_NOT_ALLOWED_TO_FAIL)
);
.unwrap_or_else(|| {
self.backend.child_storage(child_info, key).expect(EXT_NOT_ALLOWED_TO_FAIL)
});
trace!(target: "state", "{:04x}: GetChild({}) {}={:?}",
self.id,
@@ -259,19 +256,15 @@ where
result
}
fn child_storage_hash(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>> {
fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>> {
let _guard = guard();
let result = self.overlay
let result = self
.overlay
.child_storage(child_info, key)
.map(|x| x.map(|x| H::hash(x)))
.unwrap_or_else(||
self.backend.child_storage_hash(child_info, key)
.expect(EXT_NOT_ALLOWED_TO_FAIL)
);
.unwrap_or_else(|| {
self.backend.child_storage_hash(child_info, key).expect(EXT_NOT_ALLOWED_TO_FAIL)
});
trace!(target: "state", "{:04x}: ChildHash({}) {}={:?}",
self.id,
@@ -299,16 +292,13 @@ where
result
}
fn exists_child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> bool {
fn exists_child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> bool {
let _guard = guard();
let result = match self.overlay.child_storage(child_info, key) {
Some(x) => x.is_some(),
_ => self.backend
_ => self
.backend
.exists_child_storage(child_info, key)
.expect(EXT_NOT_ALLOWED_TO_FAIL),
};
@@ -323,7 +313,8 @@ where
}
fn next_storage_key(&self, key: &[u8]) -> Option<StorageKey> {
let mut next_backend_key = self.backend.next_storage_key(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
let mut next_backend_key =
self.backend.next_storage_key(key).expect(EXT_NOT_ALLOWED_TO_FAIL);
let mut overlay_changes = self.overlay.iter_after(key).peekable();
match (&next_backend_key, overlay_changes.peek()) {
@@ -343,9 +334,10 @@ where
// If the `backend_key` and `overlay_key` are equal, it means that we need
// to search for the next backend key, because the overlay has overwritten
// this key.
next_backend_key = self.backend.next_storage_key(
&overlay_key.0,
).expect(EXT_NOT_ALLOWED_TO_FAIL);
next_backend_key = self
.backend
.next_storage_key(&overlay_key.0)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
}
}
@@ -358,18 +350,13 @@ where
}
}
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageKey> {
let mut next_backend_key = self.backend
fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageKey> {
let mut next_backend_key = self
.backend
.next_child_storage_key(child_info, key)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
let mut overlay_changes = self.overlay.child_iter_after(
child_info.storage_key(),
key
).peekable();
let mut overlay_changes =
self.overlay.child_iter_after(child_info.storage_key(), key).peekable();
match (&next_backend_key, overlay_changes.peek()) {
(_, None) => next_backend_key,
@@ -388,10 +375,10 @@ where
// If the `backend_key` and `overlay_key` are equal, it means that we need
// to search for the next backend key, because the overlay has overwritten
// this key.
next_backend_key = self.backend.next_child_storage_key(
child_info,
&overlay_key.0,
).expect(EXT_NOT_ALLOWED_TO_FAIL);
next_backend_key = self
.backend
.next_child_storage_key(child_info, &overlay_key.0)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
}
}
@@ -408,7 +395,7 @@ where
let _guard = guard();
if is_child_storage_key(&key) {
warn!(target: "trie", "Refuse to directly set child storage key");
return;
return
}
// NOTE: be careful about touching the key names used outside substrate!
@@ -448,11 +435,7 @@ where
self.overlay.set_child_storage(child_info, key, value);
}
fn kill_child_storage(
&mut self,
child_info: &ChildInfo,
limit: Option<u32>,
) -> (bool, u32) {
fn kill_child_storage(&mut self, child_info: &ChildInfo, limit: Option<u32>) -> (bool, u32) {
trace!(target: "state", "{:04x}: KillChild({})",
self.id,
HexDisplay::from(&child_info.storage_key()),
@@ -472,7 +455,7 @@ where
if sp_core::storage::well_known_keys::starts_with_child_storage_key(prefix) {
warn!(target: "trie", "Refuse to directly clear prefix that is part or contains of child storage key");
return (false, 0);
return (false, 0)
}
self.mark_dirty();
@@ -498,11 +481,7 @@ where
self.limit_remove_from_backend(Some(child_info), Some(prefix), limit)
}
fn storage_append(
&mut self,
key: Vec<u8>,
value: Vec<u8>,
) {
fn storage_append(&mut self, key: Vec<u8>, value: Vec<u8>) {
trace!(target: "state", "{:04x}: Append {}={}",
self.id,
HexDisplay::from(&key),
@@ -513,10 +492,9 @@ where
self.mark_dirty();
let backend = &mut self.backend;
let current_value = self.overlay.value_mut_or_insert_with(
&key,
|| backend.storage(&key).expect(EXT_NOT_ALLOWED_TO_FAIL).unwrap_or_default()
);
let current_value = self.overlay.value_mut_or_insert_with(&key, || {
backend.storage(&key).expect(EXT_NOT_ALLOWED_TO_FAIL).unwrap_or_default()
});
StorageAppend::new(current_value).append(value);
}
@@ -527,7 +505,7 @@ where
self.id,
HexDisplay::from(&root.as_ref()),
);
return root.encode();
return root.encode()
}
let root = self.overlay.storage_root(self.backend, self.storage_transaction_cache);
@@ -535,10 +513,7 @@ where
root.encode()
}
fn child_storage_root(
&mut self,
child_info: &ChildInfo,
) -> Vec<u8> {
fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec<u8> {
let _guard = guard();
let storage_key = child_info.storage_key();
let prefixed_storage_key = child_info.prefixed_storage_key();
@@ -546,9 +521,7 @@ where
let root = self
.storage(prefixed_storage_key.as_slice())
.and_then(|k| Decode::decode(&mut &k[..]).ok())
.unwrap_or_else(
|| empty_child_trie_root::<Layout<H>>()
);
.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>());
trace!(target: "state", "{:04x}: ChildRoot({})(cached) {}",
self.id,
HexDisplay::from(&storage_key),
@@ -587,9 +560,7 @@ where
let root = self
.storage(prefixed_storage_key.as_slice())
.and_then(|k| Decode::decode(&mut &k[..]).ok())
.unwrap_or_else(
|| empty_child_trie_root::<Layout<H>>()
);
.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>());
trace!(target: "state", "{:04x}: ChildRoot({})(no_change) {}",
self.id,
HexDisplay::from(&storage_key.as_ref()),
@@ -625,10 +596,8 @@ where
index,
HexDisplay::from(&hash),
);
self.overlay.add_transaction_index(IndexOperation::Renew {
extrinsic: index,
hash: hash.to_vec(),
});
self.overlay
.add_transaction_index(IndexOperation::Renew { extrinsic: index, hash: hash.to_vec() });
}
#[cfg(not(feature = "std"))]
@@ -639,7 +608,8 @@ where
#[cfg(feature = "std")]
fn storage_changes_root(&mut self, mut parent_hash: &[u8]) -> Result<Option<Vec<u8>>, ()> {
let _guard = guard();
if let Some(ref root) = self.storage_transaction_cache.changes_trie_transaction_storage_root {
if let Some(ref root) = self.storage_transaction_cache.changes_trie_transaction_storage_root
{
trace!(
target: "state",
"{:04x}: ChangesRoot({})(cached) {:?}",
@@ -653,13 +623,13 @@ where
let root = self.overlay.changes_trie_root(
self.backend,
self.changes_trie_state.as_ref(),
Decode::decode(&mut parent_hash).map_err(|e|
Decode::decode(&mut parent_hash).map_err(|e| {
trace!(
target: "state",
"Failed to decode changes root parent hash: {}",
e,
)
)?,
})?,
true,
self.storage_transaction_cache,
);
@@ -693,13 +663,15 @@ where
for _ in 0..self.overlay.transaction_depth() {
self.overlay.rollback_transaction().expect(BENCHMARKING_FN);
}
self.overlay.drain_storage_changes(
self.backend,
#[cfg(feature = "std")]
None,
Default::default(),
self.storage_transaction_cache,
).expect(EXT_NOT_ALLOWED_TO_FAIL);
self.overlay
.drain_storage_changes(
self.backend,
#[cfg(feature = "std")]
None,
Default::default(),
self.storage_transaction_cache,
)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
self.backend.wipe().expect(EXT_NOT_ALLOWED_TO_FAIL);
self.mark_dirty();
self.overlay
@@ -711,19 +683,24 @@ where
for _ in 0..self.overlay.transaction_depth() {
self.overlay.commit_transaction().expect(BENCHMARKING_FN);
}
let changes = self.overlay.drain_storage_changes(
self.backend,
#[cfg(feature = "std")]
None,
Default::default(),
self.storage_transaction_cache,
).expect(EXT_NOT_ALLOWED_TO_FAIL);
self.backend.commit(
changes.transaction_storage_root,
changes.transaction,
changes.main_storage_changes,
changes.child_storage_changes,
).expect(EXT_NOT_ALLOWED_TO_FAIL);
let changes = self
.overlay
.drain_storage_changes(
self.backend,
#[cfg(feature = "std")]
None,
Default::default(),
self.storage_transaction_cache,
)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
self.backend
.commit(
changes.transaction_storage_root,
changes.transaction,
changes.main_storage_changes,
changes.child_storage_changes,
)
.expect(EXT_NOT_ALLOWED_TO_FAIL);
self.mark_dirty();
self.overlay
.enter_runtime()
@@ -775,13 +752,13 @@ where
self.backend.apply_to_keys_while(child_info, prefix, |key| {
if num_deleted == limit {
all_deleted = false;
return false;
return false
}
if let Some(num) = num_deleted.checked_add(1) {
num_deleted = num;
} else {
all_deleted = false;
return false;
return false
}
if let Some(child_info) = child_info {
self.overlay.set_child_storage(child_info, key.to_vec(), None);
@@ -840,7 +817,7 @@ impl<'a> StorageAppend<'a> {
"Failed to append value, resetting storage item to `[value]`.",
);
value.encode()
}
},
};
}
}
@@ -896,7 +873,10 @@ where
}
}
fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), sp_externalities::Error> {
fn deregister_extension_by_type_id(
&mut self,
type_id: TypeId,
) -> Result<(), sp_externalities::Error> {
if let Some(ref mut extensions) = self.extensions {
if extensions.deregister(type_id) {
Ok(())
@@ -912,24 +892,19 @@ where
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
use num_traits::Zero;
use codec::Encode;
use sp_core::{
H256,
Blake2Hasher,
map,
storage::{
Storage,
StorageChild,
well_known_keys::EXTRINSIC_INDEX,
},
};
use crate::{
changes_trie::{
Configuration as ChangesTrieConfiguration,
InMemoryStorage as TestChangesTrieStorage,
}, InMemoryBackend,
Configuration as ChangesTrieConfiguration, InMemoryStorage as TestChangesTrieStorage,
},
InMemoryBackend,
};
use codec::Encode;
use hex_literal::hex;
use num_traits::Zero;
use sp_core::{
map,
storage::{well_known_keys::EXTRINSIC_INDEX, Storage, StorageChild},
Blake2Hasher, H256,
};
type TestBackend = InMemoryBackend<Blake2Hasher>;
@@ -947,10 +922,7 @@ mod tests {
}
fn changes_trie_config() -> ChangesTrieConfiguration {
ChangesTrieConfiguration {
digest_interval: 0,
digest_levels: 0,
}
ChangesTrieConfiguration { digest_interval: 0, digest_levels: 0 }
}
#[test]
@@ -1013,8 +985,9 @@ mod tests {
vec![20] => vec![20],
vec![40] => vec![40]
],
children_default: map![]
}.into();
children_default: map![],
}
.into();
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
@@ -1056,8 +1029,9 @@ mod tests {
top: map![
vec![30] => vec![30]
],
children_default: map![]
}.into();
children_default: map![],
}
.into();
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
@@ -1087,7 +1061,8 @@ mod tests {
child_info: child_info.to_owned(),
}
],
}.into();
}
.into();
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
@@ -1131,7 +1106,8 @@ mod tests {
child_info: child_info.to_owned(),
}
],
}.into();
}
.into();
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
@@ -1142,10 +1118,7 @@ mod tests {
);
assert_eq!(ext.child_storage(child_info, &[20]), None);
assert_eq!(
ext.child_storage_hash(child_info, &[20]),
None,
);
assert_eq!(ext.child_storage_hash(child_info, &[20]), None,);
assert_eq!(ext.child_storage(child_info, &[30]), Some(vec![31]));
assert_eq!(
@@ -1170,7 +1143,8 @@ mod tests {
child_info: child_info.to_owned(),
}
],
}.into();
}
.into();
let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None);
@@ -18,13 +18,13 @@
//! State machine in memory backend.
use crate::{
StorageKey, StorageValue, StorageCollection, trie_backend::TrieBackend, backend::Backend,
backend::Backend, trie_backend::TrieBackend, StorageCollection, StorageKey, StorageValue,
};
use std::collections::{BTreeMap, HashMap};
use hash_db::Hasher;
use sp_trie::{MemoryDB, empty_trie_root, Layout};
use codec::Codec;
use hash_db::Hasher;
use sp_core::storage::{ChildInfo, Storage};
use sp_trie::{empty_trie_root, Layout, MemoryDB};
use std::collections::{BTreeMap, HashMap};
/// Create a new empty instance of in-memory backend.
pub fn new_in_mem<H: Hasher>() -> TrieBackend<MemoryDB<H>, H>
@@ -40,9 +40,7 @@ where
H::Out: Codec + Ord,
{
/// Copy the state, with applied updates
pub fn update<
T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>
>(
pub fn update<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
&self,
changes: T,
) -> Self {
@@ -52,19 +50,16 @@ where
}
/// Insert values into backend trie.
pub fn insert<
T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>
>(
pub fn insert<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
&mut self,
changes: T,
) {
let (top, child) = changes.into_iter().partition::<Vec<_>, _>(|v| v.0.is_none());
let (root, transaction) = self.full_storage_root(
top.iter().map(|(_, v)| v).flatten().map(|(k, v)| (&k[..], v.as_deref())),
child.iter()
.filter_map(|v|
v.0.as_ref().map(|c| (c, v.1.iter().map(|(k, v)| (&k[..], v.as_deref()))))
),
child.iter().filter_map(|v| {
v.0.as_ref().map(|c| (c, v.1.iter().map(|(k, v)| (&k[..], v.as_deref()))))
}),
);
self.apply_transaction(root, transaction);
@@ -115,7 +110,9 @@ where
fn from(inner: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>) -> Self {
let mut backend = new_in_mem();
backend.insert(
inner.into_iter().map(|(k, m)| (k, m.into_iter().map(|(k, v)| (k, Some(v))).collect())),
inner
.into_iter()
.map(|(k, m)| (k, m.into_iter().map(|(k, v)| (k, Some(v))).collect())),
);
backend
}
@@ -126,8 +123,11 @@ where
H::Out: Codec + Ord,
{
fn from(inners: Storage) -> Self {
let mut inner: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>
= inners.children_default.into_iter().map(|(_k, c)| (Some(c.child_info), c.data)).collect();
let mut inner: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>> = inners
.children_default
.into_iter()
.map(|(_k, c)| (Some(c.child_info), c.data))
.collect();
inner.insert(None, inners.top);
inner.into()
}
@@ -144,16 +144,13 @@ where
}
}
impl<H: Hasher> From<Vec<(Option<ChildInfo>, StorageCollection)>>
for TrieBackend<MemoryDB<H>, H>
impl<H: Hasher> From<Vec<(Option<ChildInfo>, StorageCollection)>> for TrieBackend<MemoryDB<H>, H>
where
H::Out: Codec + Ord,
{
fn from(
inner: Vec<(Option<ChildInfo>, StorageCollection)>,
) -> Self {
let mut expanded: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>
= HashMap::new();
fn from(inner: Vec<(Option<ChildInfo>, StorageCollection)>) -> Self {
let mut expanded: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>> =
HashMap::new();
for (child_info, key_values) in inner {
let entry = expanded.entry(child_info).or_default();
for (key, value) in key_values {
@@ -169,8 +166,8 @@ where
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::traits::BlakeTwo256;
use crate::backend::Backend;
use sp_runtime::traits::BlakeTwo256;
/// Assert in memory backend with only child trie keys works as trie backend.
#[test]
@@ -178,15 +175,10 @@ mod tests {
let storage = new_in_mem::<BlakeTwo256>();
let child_info = ChildInfo::new_default(b"1");
let child_info = &child_info;
let mut storage = storage.update(
vec![(
Some(child_info.clone()),
vec![(b"2".to_vec(), Some(b"3".to_vec()))]
)]
);
let mut storage = storage
.update(vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])]);
let trie_backend = storage.as_trie_backend().unwrap();
assert_eq!(trie_backend.child_storage(child_info, b"2").unwrap(),
Some(b"3".to_vec()));
assert_eq!(trie_backend.child_storage(child_info, b"2").unwrap(), Some(b"3".to_vec()));
let storage_key = child_info.prefixed_storage_key();
assert!(trie_backend.storage(storage_key.as_slice()).unwrap().is_some());
}
@@ -196,8 +188,10 @@ mod tests {
let mut storage = new_in_mem::<BlakeTwo256>();
let child_info = ChildInfo::new_default(b"1");
storage.insert(vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])]);
storage.insert(vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])]);
storage
.insert(vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])]);
storage
.insert(vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])]);
assert_eq!(storage.child_storage(&child_info, &b"2"[..]), Ok(Some(b"3".to_vec())));
assert_eq!(storage.child_storage(&child_info, &b"1"[..]), Ok(Some(b"3".to_vec())));
File diff suppressed because it is too large Load Diff
@@ -17,17 +17,19 @@
//! Houses the code that implements the transactional overlay storage.
use super::{StorageKey, StorageValue, Extrinsics};
use super::{Extrinsics, StorageKey, StorageValue};
#[cfg(feature = "std")]
use std::collections::HashSet as Set;
#[cfg(not(feature = "std"))]
use sp_std::collections::btree_set::BTreeSet as Set;
#[cfg(feature = "std")]
use std::collections::HashSet as Set;
use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
use sp_std::hash::Hash;
use smallvec::SmallVec;
use crate::warn;
use smallvec::SmallVec;
use sp_std::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
hash::Hash,
};
const PROOF_OVERLAY_NON_EMPTY: &str = "\
An OverlayValue is always created with at least one transaction and dropped as soon
@@ -82,9 +84,7 @@ pub struct OverlayedEntry<V> {
impl<V> Default for OverlayedEntry<V> {
fn default() -> Self {
Self {
transactions: SmallVec::new(),
}
Self { transactions: SmallVec::new() }
}
}
@@ -142,7 +142,9 @@ impl<V> OverlayedEntry<V> {
/// Unique list of extrinsic indices which modified the value.
pub fn extrinsics(&self) -> BTreeSet<u32> {
let mut set = BTreeSet::new();
self.transactions.iter().for_each(|t| t.extrinsics.copy_extrinsics_into(&mut set));
self.transactions
.iter()
.for_each(|t| t.extrinsics.copy_extrinsics_into(&mut set));
set
}
@@ -165,17 +167,9 @@ impl<V> OverlayedEntry<V> {
///
/// This makes sure that the old version is not overwritten and can be properly
/// rolled back when required.
fn set(
&mut self,
value: V,
first_write_in_tx: bool,
at_extrinsic: Option<u32>,
) {
fn set(&mut self, value: V, first_write_in_tx: bool, at_extrinsic: Option<u32>) {
if first_write_in_tx || self.transactions.is_empty() {
self.transactions.push(InnerValue {
value,
extrinsics: Default::default(),
});
self.transactions.push(InnerValue { value, extrinsics: Default::default() });
} else {
*self.value_mut() = value;
}
@@ -223,9 +217,9 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
/// Get an optional reference to the value stored for the specified key.
pub fn get<Q>(&self, key: &Q) -> Option<&OverlayedEntry<V>>
where
K: sp_std::borrow::Borrow<Q>,
Q: Ord + ?Sized,
where
K: sp_std::borrow::Borrow<Q>,
Q: Ord + ?Sized,
{
self.changes.get(key)
}
@@ -233,24 +227,19 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
/// Set a new value for the specified key.
///
/// Can be rolled back or committed when called inside a transaction.
pub fn set(
&mut self,
key: K,
value: V,
at_extrinsic: Option<u32>,
) {
pub fn set(&mut self, key: K, value: V, at_extrinsic: Option<u32>) {
let overlayed = self.changes.entry(key.clone()).or_default();
overlayed.set(value, insert_dirty(&mut self.dirty_keys, key), at_extrinsic);
}
/// Get a list of all changes as seen by current transaction.
pub fn changes(&self) -> impl Iterator<Item=(&K, &OverlayedEntry<V>)> {
pub fn changes(&self) -> impl Iterator<Item = (&K, &OverlayedEntry<V>)> {
self.changes.iter()
}
/// Get a list of all changes as seen by current transaction, consumes
/// the overlay.
pub fn into_changes(self) -> impl Iterator<Item=(K, OverlayedEntry<V>)> {
pub fn into_changes(self) -> impl Iterator<Item = (K, OverlayedEntry<V>)> {
self.changes.into_iter()
}
@@ -258,7 +247,7 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
///
/// Panics:
/// Panics if there are open transactions: `transaction_depth() > 0`
pub fn drain_commited(self) -> impl Iterator<Item=(K, V)> {
pub fn drain_commited(self) -> impl Iterator<Item = (K, V)> {
assert!(self.transaction_depth() == 0, "Drain is not allowed with open transactions.");
self.changes.into_iter().map(|(k, mut v)| (k, v.pop_transaction().value))
}
@@ -276,7 +265,7 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
/// Calling this while already inside the runtime will return an error.
pub fn enter_runtime(&mut self) -> Result<(), AlreadyInRuntime> {
if let ExecutionMode::Runtime = self.execution_mode {
return Err(AlreadyInRuntime);
return Err(AlreadyInRuntime)
}
self.execution_mode = ExecutionMode::Runtime;
self.num_client_transactions = self.transaction_depth();
@@ -289,7 +278,7 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
/// Calling this while already outside the runtime will return an error.
pub fn exit_runtime(&mut self) -> Result<(), NotInRuntime> {
if let ExecutionMode::Client = self.execution_mode {
return Err(NotInRuntime);
return Err(NotInRuntime)
}
self.execution_mode = ExecutionMode::Client;
if self.has_open_runtime_transactions() {
@@ -341,11 +330,13 @@ impl<K: Ord + Hash + Clone, V> OverlayedMap<K, V> {
}
for key in self.dirty_keys.pop().ok_or(NoOpenTransaction)? {
let overlayed = self.changes.get_mut(&key).expect("\
let overlayed = self.changes.get_mut(&key).expect(
"\
A write to an OverlayedValue is recorded in the dirty key set. Before an
OverlayedValue is removed, its containing dirty set is removed. This
function is only called for keys that are in the dirty set. qed\
");
",
);
if rollback {
overlayed.pop_transaction();
@@ -443,9 +434,12 @@ mod test {
type Drained<'a> = Vec<(&'a [u8], Option<&'a [u8]>)>;
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().into_iter().collect()))
}).collect();
let is: Changes = is
.changes()
.map(|(k, v)| {
(k.as_ref(), (v.value().map(AsRef::as_ref), v.extrinsics().into_iter().collect()))
})
.collect();
assert_eq!(&is, expected);
}
@@ -453,7 +447,8 @@ mod test {
let is = is.drain_commited().collect::<Vec<_>>();
let expected = expected
.iter()
.map(|(k, v)| (k.to_vec(), v.0.map(From::from))).collect::<Vec<_>>();
.map(|(k, v)| (k.to_vec(), v.0.map(From::from)))
.collect::<Vec<_>>();
assert_eq!(is, expected);
}
@@ -461,7 +456,8 @@ mod test {
let is = is.drain_commited().collect::<Vec<_>>();
let expected = expected
.iter()
.map(|(k, v)| (k.to_vec(), v.map(From::from))).collect::<Vec<_>>();
.map(|(k, v)| (k.to_vec(), v.map(From::from)))
.collect::<Vec<_>>();
assert_eq!(is, expected);
}
@@ -474,10 +470,7 @@ mod test {
changeset.set(b"key1".to_vec(), Some(b"val1".to_vec()), Some(2));
changeset.set(b"key0".to_vec(), Some(b"val0-1".to_vec()), Some(9));
assert_drained(changeset, vec![
(b"key0", Some(b"val0-1")),
(b"key1", Some(b"val1")),
]);
assert_drained(changeset, vec![(b"key0", Some(b"val0-1")), (b"key1", Some(b"val1"))]);
}
#[test]
@@ -599,10 +592,8 @@ mod test {
changeset.rollback_transaction().unwrap();
assert_eq!(changeset.transaction_depth(), 0);
let rolled_back: Changes = vec![
(b"key0", (Some(b"val0-1"), vec![1, 10])),
(b"key1", (Some(b"val1"), vec![1])),
];
let rolled_back: Changes =
vec![(b"key0", (Some(b"val0-1"), vec![1, 10])), (b"key1", (Some(b"val1"), vec![1]))];
assert_changes(&changeset, &rolled_back);
assert_drained_changes(changeset, rolled_back);
@@ -676,21 +667,27 @@ mod test {
changeset.clear_where(|k, _| k.starts_with(b"del"), Some(5));
assert_changes(&changeset, &vec![
(b"del1", (None, vec![3, 5])),
(b"del2", (None, vec![4, 5])),
(b"key0", (Some(b"val0"), vec![1])),
(b"key1", (Some(b"val1"), vec![2])),
]);
assert_changes(
&changeset,
&vec![
(b"del1", (None, vec![3, 5])),
(b"del2", (None, vec![4, 5])),
(b"key0", (Some(b"val0"), vec![1])),
(b"key1", (Some(b"val1"), vec![2])),
],
);
changeset.rollback_transaction().unwrap();
assert_changes(&changeset, &vec![
(b"del1", (Some(b"delval1"), vec![3])),
(b"del2", (Some(b"delval2"), vec![4])),
(b"key0", (Some(b"val0"), vec![1])),
(b"key1", (Some(b"val1"), vec![2])),
]);
assert_changes(
&changeset,
&vec![
(b"del1", (Some(b"delval1"), vec![3])),
(b"del2", (Some(b"delval2"), vec![4])),
(b"key0", (Some(b"val0"), vec![1])),
(b"key1", (Some(b"val1"), vec![2])),
],
);
}
#[test]
@@ -708,29 +705,52 @@ mod test {
changeset.set(b"key11".to_vec(), Some(b"val11".to_vec()), Some(11));
assert_eq!(changeset.changes_after(b"key0").next().unwrap().0, b"key1");
assert_eq!(changeset.changes_after(b"key0").next().unwrap().1.value(), Some(&b"val1".to_vec()));
assert_eq!(
changeset.changes_after(b"key0").next().unwrap().1.value(),
Some(&b"val1".to_vec())
);
assert_eq!(changeset.changes_after(b"key1").next().unwrap().0, b"key11");
assert_eq!(changeset.changes_after(b"key1").next().unwrap().1.value(), Some(&b"val11".to_vec()));
assert_eq!(
changeset.changes_after(b"key1").next().unwrap().1.value(),
Some(&b"val11".to_vec())
);
assert_eq!(changeset.changes_after(b"key11").next().unwrap().0, b"key2");
assert_eq!(changeset.changes_after(b"key11").next().unwrap().1.value(), Some(&b"val2".to_vec()));
assert_eq!(
changeset.changes_after(b"key11").next().unwrap().1.value(),
Some(&b"val2".to_vec())
);
assert_eq!(changeset.changes_after(b"key2").next().unwrap().0, b"key3");
assert_eq!(changeset.changes_after(b"key2").next().unwrap().1.value(), Some(&b"val3".to_vec()));
assert_eq!(
changeset.changes_after(b"key2").next().unwrap().1.value(),
Some(&b"val3".to_vec())
);
assert_eq!(changeset.changes_after(b"key3").next().unwrap().0, b"key4");
assert_eq!(changeset.changes_after(b"key3").next().unwrap().1.value(), Some(&b"val4".to_vec()));
assert_eq!(
changeset.changes_after(b"key3").next().unwrap().1.value(),
Some(&b"val4".to_vec())
);
assert_eq!(changeset.changes_after(b"key4").next(), None);
changeset.rollback_transaction().unwrap();
assert_eq!(changeset.changes_after(b"key0").next().unwrap().0, b"key1");
assert_eq!(changeset.changes_after(b"key0").next().unwrap().1.value(), Some(&b"val1".to_vec()));
assert_eq!(
changeset.changes_after(b"key0").next().unwrap().1.value(),
Some(&b"val1".to_vec())
);
assert_eq!(changeset.changes_after(b"key1").next().unwrap().0, b"key2");
assert_eq!(changeset.changes_after(b"key1").next().unwrap().1.value(), Some(&b"val2".to_vec()));
assert_eq!(
changeset.changes_after(b"key1").next().unwrap().1.value(),
Some(&b"val2".to_vec())
);
assert_eq!(changeset.changes_after(b"key11").next().unwrap().0, b"key2");
assert_eq!(changeset.changes_after(b"key11").next().unwrap().1.value(), Some(&b"val2".to_vec()));
assert_eq!(
changeset.changes_after(b"key11").next().unwrap().1.value(),
Some(&b"val2".to_vec())
);
assert_eq!(changeset.changes_after(b"key2").next(), None);
assert_eq!(changeset.changes_after(b"key3").next(), None);
assert_eq!(changeset.changes_after(b"key4").next(), None);
}
#[test]
@@ -790,9 +810,7 @@ mod test {
changeset.commit_transaction().unwrap();
assert_eq!(changeset.transaction_depth(), 0);
assert_drained(changeset, vec![
(b"key0", Some(b"val0")),
]);
assert_drained(changeset, vec![(b"key0", Some(b"val0"))]);
}
#[test]
@@ -20,36 +20,35 @@
mod changeset;
mod offchain;
pub use offchain::OffchainOverlayedChanges;
use crate::{
backend::Backend,
stats::StateMachineStats,
};
use sp_std::{vec::Vec, any::{TypeId, Any}, boxed::Box};
use self::changeset::OverlayedChangeSet;
use crate::{backend::Backend, stats::StateMachineStats};
pub use offchain::OffchainOverlayedChanges;
use sp_std::{
any::{Any, TypeId},
boxed::Box,
vec::Vec,
};
use crate::{changes_trie::BlockNumber, DefaultError};
#[cfg(feature = "std")]
use crate::{
changes_trie::{build_changes_trie, State as ChangesTrieState},
ChangesTrieTransaction,
changes_trie::{
build_changes_trie,
State as ChangesTrieState,
},
};
use crate::changes_trie::BlockNumber;
#[cfg(feature = "std")]
use std::collections::{HashMap as Map, hash_map::Entry as MapEntry};
use codec::{Decode, Encode};
use hash_db::Hasher;
use sp_core::{
offchain::OffchainOverlayedChange,
storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo},
};
use sp_externalities::{Extension, Extensions};
#[cfg(not(feature = "std"))]
use sp_std::collections::btree_map::{BTreeMap as Map, Entry as MapEntry};
use sp_std::collections::btree_set::BTreeSet;
use codec::{Decode, Encode};
use sp_core::storage::{well_known_keys::EXTRINSIC_INDEX, ChildInfo};
use sp_core::offchain::OffchainOverlayedChange;
use hash_db::Hasher;
use crate::DefaultError;
use sp_externalities::{Extensions, Extension};
#[cfg(feature = "std")]
use std::collections::{hash_map::Entry as MapEntry, HashMap as Map};
pub use self::changeset::{OverlayedValue, NoOpenTransaction, AlreadyInRuntime, NotInRuntime};
pub use self::changeset::{AlreadyInRuntime, NoOpenTransaction, NotInRuntime, OverlayedValue};
/// Changes that are made outside of extrinsics are marked with this index;
pub const NO_EXTRINSIC_INDEX: u32 = 0xffffffff;
@@ -129,7 +128,7 @@ pub enum IndexOperation {
extrinsic: u32,
/// Referenced index hash.
hash: Vec<u8>,
}
},
}
/// A storage changes structure that can be generated by the data collected in [`OverlayedChanges`].
@@ -169,7 +168,9 @@ pub struct StorageChanges<Transaction, H: Hasher, N: BlockNumber> {
#[cfg(feature = "std")]
impl<Transaction, H: Hasher, N: BlockNumber> StorageChanges<Transaction, H, N> {
/// Deconstruct into the inner values
pub fn into_inner(self) -> (
pub fn into_inner(
self,
) -> (
StorageCollection,
ChildStorageCollection,
OffchainChangesCollection,
@@ -216,7 +217,9 @@ impl<Transaction, H: Hasher, N: BlockNumber> StorageTransactionCache<Transaction
}
}
impl<Transaction, H: Hasher, N: BlockNumber> Default for StorageTransactionCache<Transaction, H, N> {
impl<Transaction, H: Hasher, N: BlockNumber> Default
for StorageTransactionCache<Transaction, H, N>
{
fn default() -> Self {
Self {
transaction: None,
@@ -231,7 +234,9 @@ impl<Transaction, H: Hasher, N: BlockNumber> Default for StorageTransactionCache
}
}
impl<Transaction: Default, H: Hasher, N: BlockNumber> Default for StorageChanges<Transaction, H, N> {
impl<Transaction: Default, H: Hasher, N: BlockNumber> Default
for StorageChanges<Transaction, H, N>
{
fn default() -> Self {
Self {
main_storage_changes: Default::default(),
@@ -325,12 +330,10 @@ impl OverlayedChanges {
self.stats.tally_write_overlay(size_write);
let storage_key = child_info.storage_key().to_vec();
let top = &self.top;
let (changeset, info) = self.children.entry(storage_key).or_insert_with(||
(
top.spawn_child(),
child_info.clone()
)
);
let (changeset, info) = self
.children
.entry(storage_key)
.or_insert_with(|| (top.spawn_child(), child_info.clone()));
let updatable = info.try_update(child_info);
debug_assert!(updatable);
changeset.set(key, val, extrinsic_index);
@@ -339,19 +342,14 @@ impl OverlayedChanges {
/// Clear child storage of given storage key.
///
/// Can be rolled back or committed when called inside a transaction.
pub(crate) fn clear_child_storage(
&mut self,
child_info: &ChildInfo,
) {
pub(crate) fn clear_child_storage(&mut self, child_info: &ChildInfo) {
let extrinsic_index = self.extrinsic_index();
let storage_key = child_info.storage_key().to_vec();
let top = &self.top;
let (changeset, info) = self.children.entry(storage_key).or_insert_with(||
(
top.spawn_child(),
child_info.clone()
)
);
let (changeset, info) = self
.children
.entry(storage_key)
.or_insert_with(|| (top.spawn_child(), child_info.clone()));
let updatable = info.try_update(child_info);
debug_assert!(updatable);
changeset.clear_where(|_, _| true, extrinsic_index);
@@ -367,20 +365,14 @@ impl OverlayedChanges {
/// Removes all key-value pairs which keys share the given prefix.
///
/// Can be rolled back or committed when called inside a transaction
pub(crate) fn clear_child_prefix(
&mut self,
child_info: &ChildInfo,
prefix: &[u8],
) {
pub(crate) fn clear_child_prefix(&mut self, child_info: &ChildInfo, prefix: &[u8]) {
let extrinsic_index = self.extrinsic_index();
let storage_key = child_info.storage_key().to_vec();
let top = &self.top;
let (changeset, info) = self.children.entry(storage_key).or_insert_with(||
(
top.spawn_child(),
child_info.clone()
)
);
let (changeset, info) = self
.children
.entry(storage_key)
.or_insert_with(|| (top.spawn_child(), child_info.clone()));
let updatable = info.try_update(child_info);
debug_assert!(updatable);
changeset.clear_where(|key, _| key.starts_with(prefix), extrinsic_index);
@@ -417,11 +409,14 @@ impl OverlayedChanges {
pub fn rollback_transaction(&mut self) -> Result<(), NoOpenTransaction> {
self.top.rollback_transaction()?;
retain_map(&mut self.children, |_, (changeset, _)| {
changeset.rollback_transaction()
changeset
.rollback_transaction()
.expect("Top and children changesets are started in lockstep; qed");
!changeset.is_empty()
});
self.offchain.overlay_mut().rollback_transaction()
self.offchain
.overlay_mut()
.rollback_transaction()
.expect("Top and offchain changesets are started in lockstep; qed");
Ok(())
}
@@ -433,10 +428,13 @@ impl OverlayedChanges {
pub fn commit_transaction(&mut self) -> Result<(), NoOpenTransaction> {
self.top.commit_transaction()?;
for (_, (changeset, _)) in self.children.iter_mut() {
changeset.commit_transaction()
changeset
.commit_transaction()
.expect("Top and children changesets are started in lockstep; qed");
}
self.offchain.overlay_mut().commit_transaction()
self.offchain
.overlay_mut()
.commit_transaction()
.expect("Top and offchain changesets are started in lockstep; qed");
Ok(())
}
@@ -448,10 +446,13 @@ impl OverlayedChanges {
pub fn enter_runtime(&mut self) -> Result<(), AlreadyInRuntime> {
self.top.enter_runtime()?;
for (_, (changeset, _)) in self.children.iter_mut() {
changeset.enter_runtime()
changeset
.enter_runtime()
.expect("Top and children changesets are entering runtime in lockstep; qed")
}
self.offchain.overlay_mut().enter_runtime()
self.offchain
.overlay_mut()
.enter_runtime()
.expect("Top and offchain changesets are started in lockstep; qed");
Ok(())
}
@@ -463,10 +464,13 @@ impl OverlayedChanges {
pub fn exit_runtime(&mut self) -> Result<(), NotInRuntime> {
self.top.exit_runtime()?;
for (_, (changeset, _)) in self.children.iter_mut() {
changeset.exit_runtime()
changeset
.exit_runtime()
.expect("Top and children changesets are entering runtime in lockstep; qed");
}
self.offchain.overlay_mut().exit_runtime()
self.offchain
.overlay_mut()
.exit_runtime()
.expect("Top and offchain changesets are started in lockstep; qed");
Ok(())
}
@@ -477,19 +481,23 @@ impl OverlayedChanges {
///
/// Panics:
/// Panics if `transaction_depth() > 0`
fn drain_committed(&mut self) -> (
impl Iterator<Item=(StorageKey, Option<StorageValue>)>,
impl Iterator<Item=(StorageKey, (impl Iterator<Item=(StorageKey, Option<StorageValue>)>, ChildInfo))>,
fn drain_committed(
&mut self,
) -> (
impl Iterator<Item = (StorageKey, Option<StorageValue>)>,
impl Iterator<
Item = (
StorageKey,
(impl Iterator<Item = (StorageKey, Option<StorageValue>)>, ChildInfo),
),
>,
) {
use sp_std::mem::take;
(
take(&mut self.top).drain_commited(),
take(&mut self.children).into_iter()
.map(|(key, (val, info))| (
key,
(val.drain_commited(), info)
)
),
take(&mut self.children)
.into_iter()
.map(|(key, (val, info))| (key, (val.drain_commited(), info))),
)
}
@@ -499,24 +507,29 @@ impl OverlayedChanges {
///
/// Panics:
/// Panics if `transaction_depth() > 0`
pub fn offchain_drain_committed(&mut self) -> impl Iterator<Item=((StorageKey, StorageKey), OffchainOverlayedChange)> {
pub fn offchain_drain_committed(
&mut self,
) -> impl Iterator<Item = ((StorageKey, StorageKey), OffchainOverlayedChange)> {
self.offchain.drain()
}
/// Get an iterator over all child changes as seen by the current transaction.
pub fn children(&self)
-> impl Iterator<Item=(impl Iterator<Item=(&StorageKey, &OverlayedValue)>, &ChildInfo)> {
pub fn children(
&self,
) -> impl Iterator<Item = (impl Iterator<Item = (&StorageKey, &OverlayedValue)>, &ChildInfo)> {
self.children.iter().map(|(_, v)| (v.0.changes(), &v.1))
}
/// Get an iterator over all top changes as been by the current transaction.
pub fn changes(&self) -> impl Iterator<Item=(&StorageKey, &OverlayedValue)> {
pub fn changes(&self) -> impl Iterator<Item = (&StorageKey, &OverlayedValue)> {
self.top.changes()
}
/// Get an optional iterator over all child changes stored under the supplied key.
pub fn child_changes(&self, key: &[u8])
-> Option<(impl Iterator<Item=(&StorageKey, &OverlayedValue)>, &ChildInfo)> {
pub fn child_changes(
&self,
key: &[u8],
) -> Option<(impl Iterator<Item = (&StorageKey, &OverlayedValue)>, &ChildInfo)> {
self.children.get(key).map(|(overlay, info)| (overlay.changes(), info))
}
@@ -527,16 +540,16 @@ impl OverlayedChanges {
/// Convert this instance with all changes into a [`StorageChanges`] instance.
#[cfg(feature = "std")]
pub fn into_storage_changes<
B: Backend<H>, H: Hasher, N: BlockNumber
>(
pub fn into_storage_changes<B: Backend<H>, H: Hasher, N: BlockNumber>(
mut self,
backend: &B,
changes_trie_state: Option<&ChangesTrieState<H, N>>,
parent_hash: H::Out,
mut cache: StorageTransactionCache<B::Transaction, H, N>,
) -> Result<StorageChanges<B::Transaction, H, N>, DefaultError>
where H::Out: Ord + Encode + 'static {
where
H::Out: Ord + Encode + 'static,
{
self.drain_storage_changes(backend, changes_trie_state, parent_hash, &mut cache)
}
@@ -544,35 +557,34 @@ impl OverlayedChanges {
pub fn drain_storage_changes<B: Backend<H>, H: Hasher, N: BlockNumber>(
&mut self,
backend: &B,
#[cfg(feature = "std")]
changes_trie_state: Option<&ChangesTrieState<H, N>>,
#[cfg(feature = "std")] changes_trie_state: Option<&ChangesTrieState<H, N>>,
parent_hash: H::Out,
mut cache: &mut StorageTransactionCache<B::Transaction, H, N>,
) -> Result<StorageChanges<B::Transaction, H, N>, DefaultError>
where H::Out: Ord + Encode + 'static {
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);
}
let (transaction, transaction_storage_root) = cache.transaction.take()
let (transaction, transaction_storage_root) = cache
.transaction
.take()
.and_then(|t| cache.transaction_storage_root.take().map(|tr| (t, tr)))
.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,
changes_trie_state,
parent_hash,
false,
&mut cache,
).map_err(|_| "Failed to generate changes trie transaction")?;
self.changes_trie_root(backend, changes_trie_state, parent_hash, false, &mut cache)
.map_err(|_| "Failed to generate changes trie transaction")?;
}
#[cfg(feature = "std")]
let changes_trie_transaction = cache.changes_trie_transaction
let changes_trie_transaction = cache
.changes_trie_transaction
.take()
.expect("Changes trie transaction was generated by `changes_trie_root`; qed");
@@ -584,7 +596,9 @@ impl OverlayedChanges {
Ok(StorageChanges {
main_storage_changes: main_storage_changes.collect(),
child_storage_changes: child_storage_changes.map(|(sk, it)| (sk, it.0.collect())).collect(),
child_storage_changes: child_storage_changes
.map(|(sk, it)| (sk, it.0.collect()))
.collect(),
offchain_storage_changes,
transaction,
transaction_storage_root,
@@ -614,7 +628,8 @@ impl OverlayedChanges {
true => Some(
self.storage(EXTRINSIC_INDEX)
.and_then(|idx| idx.and_then(|idx| Decode::decode(&mut &*idx).ok()))
.unwrap_or(NO_EXTRINSIC_INDEX)),
.unwrap_or(NO_EXTRINSIC_INDEX),
),
false => None,
}
}
@@ -628,13 +643,13 @@ impl OverlayedChanges {
backend: &B,
cache: &mut StorageTransactionCache<B::Transaction, H, N>,
) -> H::Out
where H::Out: Ord + Encode,
where
H::Out: Ord + Encode,
{
let delta = self.changes().map(|(k, v)| (&k[..], v.value().map(|v| &v[..])));
let child_delta = self.children()
.map(|(changes, info)| (info, changes.map(
|(k, v)| (&k[..], v.value().map(|v| &v[..]))
)));
let child_delta = self.children().map(|(changes, info)| {
(info, changes.map(|(k, v)| (&k[..], v.value().map(|v| &v[..]))))
});
let (root, transaction) = backend.full_storage_root(delta, child_delta);
@@ -659,14 +674,18 @@ impl OverlayedChanges {
parent_hash: H::Out,
panic_on_storage_error: bool,
cache: &mut StorageTransactionCache<B::Transaction, H, N>,
) -> Result<Option<H::Out>, ()> where H::Out: Ord + Encode + 'static {
) -> Result<Option<H::Out>, ()>
where
H::Out: Ord + Encode + 'static,
{
build_changes_trie::<_, H, N>(
backend,
changes_trie_state,
self,
parent_hash,
panic_on_storage_error,
).map(|r| {
)
.map(|r| {
let root = r.as_ref().map(|r| r.1).clone();
cache.changes_trie_transaction = Some(r.map(|(db, _, cache)| (db, cache)));
cache.changes_trie_transaction_storage_root = Some(root);
@@ -685,7 +704,7 @@ impl OverlayedChanges {
pub fn child_iter_after(
&self,
storage_key: &[u8],
key: &[u8]
key: &[u8],
) -> impl Iterator<Item = (&[u8], &OverlayedValue)> {
self.children
.get(storage_key)
@@ -716,18 +735,18 @@ impl OverlayedChanges {
#[cfg(feature = "std")]
fn retain_map<K, V, F>(map: &mut Map<K, V>, f: F)
where
K: std::cmp::Eq + std::hash::Hash,
F: FnMut(&K, &mut V) -> bool,
where
K: std::cmp::Eq + std::hash::Hash,
F: FnMut(&K, &mut V) -> bool,
{
map.retain(f);
}
#[cfg(not(feature = "std"))]
fn retain_map<K, V, F>(map: &mut Map<K, V>, mut f: F)
where
K: Ord,
F: FnMut(&K, &mut V) -> bool,
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() {
@@ -799,18 +818,13 @@ impl<'a> OverlayedExtensions<'a> {
#[cfg(test)]
mod tests {
use hex_literal::hex;
use sp_core::{Blake2Hasher, traits::Externalities};
use crate::InMemoryBackend;
use crate::ext::Ext;
use super::*;
use crate::{ext::Ext, InMemoryBackend};
use hex_literal::hex;
use sp_core::{traits::Externalities, Blake2Hasher};
use std::collections::BTreeMap;
fn assert_extrinsics(
overlay: &OverlayedChangeSet,
key: impl AsRef<[u8]>,
expected: Vec<u32>,
) {
fn assert_extrinsics(overlay: &OverlayedChangeSet, key: impl AsRef<[u8]>, expected: Vec<u32>) {
assert_eq!(
overlay.get(key.as_ref()).unwrap().extrinsics().into_iter().collect::<Vec<_>>(),
expected
@@ -863,13 +877,16 @@ mod tests {
state.commit_transaction().unwrap();
}
let offchain_data: Vec<_> = state.offchain_drain_committed().collect();
let expected: Vec<_> = expected.into_iter().map(|(key, value)| {
let change = match value {
Some(value) => OffchainOverlayedChange::SetValue(value),
None => OffchainOverlayedChange::Remove,
};
((STORAGE_PREFIX.to_vec(), key), change)
}).collect();
let expected: Vec<_> = expected
.into_iter()
.map(|(key, value)| {
let change = match value {
Some(value) => OffchainOverlayedChange::SetValue(value),
None => OffchainOverlayedChange::Remove,
};
((STORAGE_PREFIX.to_vec(), key), change)
})
.collect();
assert_eq!(offchain_data, expected);
}
@@ -904,7 +921,6 @@ mod tests {
check_offchain_content(&overlayed, 0, vec![(key.clone(), None)]);
}
#[test]
fn overlayed_storage_root_works() {
let initial: BTreeMap<_, _> = vec![
@@ -912,7 +928,9 @@ mod tests {
(b"dog".to_vec(), b"puppyXXX".to_vec()),
(b"dogglesworth".to_vec(), b"catXXX".to_vec()),
(b"doug".to_vec(), b"notadog".to_vec()),
].into_iter().collect();
]
.into_iter()
.collect();
let backend = InMemoryBackend::<Blake2Hasher>::from(initial);
let mut overlay = OverlayedChanges::default();
overlay.set_collect_extrinsics(false);
@@ -935,7 +953,8 @@ mod tests {
crate::changes_trie::disabled_state::<_, u64>(),
None,
);
const ROOT: [u8; 32] = hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
const ROOT: [u8; 32] =
hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa");
assert_eq!(&ext.storage_root()[..], &ROOT);
}
@@ -17,9 +17,9 @@
//! Overlayed changes for offchain indexing.
use super::changeset::OverlayedMap;
use sp_core::offchain::OffchainOverlayedChange;
use sp_std::prelude::Vec;
use super::changeset::OverlayedMap;
/// In-memory storage for offchain workers recoding changes for the actual offchain storage implementation.
#[derive(Debug, Clone, Default)]
@@ -52,11 +52,9 @@ impl OffchainOverlayedChanges {
/// Remove a key and its associated value from the offchain database.
pub fn remove(&mut self, prefix: &[u8], key: &[u8]) {
let _ = self.0.set(
(prefix.to_vec(), key.to_vec()),
OffchainOverlayedChange::Remove,
None,
);
let _ = self
.0
.set((prefix.to_vec(), key.to_vec()), OffchainOverlayedChange::Remove, None);
}
/// Set the value associated with a key under a prefix to the value provided.
@@ -80,7 +78,9 @@ impl OffchainOverlayedChanges {
}
/// Mutable reference to inner change set.
pub fn overlay_mut(&mut self) -> &mut OverlayedMap<(Vec<u8>, Vec<u8>), OffchainOverlayedChange> {
pub fn overlay_mut(
&mut self,
) -> &mut OverlayedMap<(Vec<u8>, Vec<u8>), OffchainOverlayedChange> {
&mut self.0
}
}
@@ -120,10 +120,10 @@ mod test {
let mut iter = ooc.into_iter();
assert_eq!(
iter.next(),
Some(
((STORAGE_PREFIX.to_vec(), b"ppp".to_vec()),
OffchainOverlayedChange::SetValue(b"rrr".to_vec()))
)
Some((
(STORAGE_PREFIX.to_vec(), b"ppp".to_vec()),
OffchainOverlayedChange::SetValue(b"rrr".to_vec())
))
);
assert_eq!(iter.next(), None);
}
@@ -17,20 +17,28 @@
//! Proving state machine backend.
use std::{sync::Arc, collections::{HashMap, hash_map::Entry}};
use parking_lot::RwLock;
use codec::{Decode, Codec, Encode};
use log::debug;
use hash_db::{Hasher, HashDB, EMPTY_PREFIX, Prefix};
use sp_trie::{
MemoryDB, empty_child_trie_root, read_trie_value_with, read_child_trie_value_with,
record_all_keys, StorageProof,
use crate::{
trie_backend::TrieBackend,
trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage},
Backend, DBValue, Error, ExecutionError,
};
pub use sp_trie::{Recorder, trie_types::{Layout, TrieError}};
use crate::trie_backend::TrieBackend;
use crate::trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage};
use crate::{Error, ExecutionError, Backend, DBValue};
use codec::{Codec, Decode, Encode};
use hash_db::{HashDB, Hasher, Prefix, EMPTY_PREFIX};
use log::debug;
use parking_lot::RwLock;
use sp_core::storage::ChildInfo;
use sp_trie::{
empty_child_trie_root, read_child_trie_value_with, read_trie_value_with, record_all_keys,
MemoryDB, StorageProof,
};
pub use sp_trie::{
trie_types::{Layout, TrieError},
Recorder,
};
use std::{
collections::{hash_map::Entry, HashMap},
sync::Arc,
};
/// Patricia trie-based backend specialized in get value proofs.
pub struct ProvingBackendRecorder<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> {
@@ -39,18 +47,15 @@ pub struct ProvingBackendRecorder<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Has
}
impl<'a, S, H> ProvingBackendRecorder<'a, S, H>
where
S: TrieBackendStorage<H>,
H: Hasher,
H::Out: Codec,
where
S: TrieBackendStorage<H>,
H: Hasher,
H::Out: Codec,
{
/// Produce proof for a key query.
pub fn storage(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, String> {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral::new(
self.backend.backend_storage(),
&mut read_overlay,
);
let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay);
let map_e = |e| format!("Trie lookup error: {}", e);
@@ -59,25 +64,24 @@ impl<'a, S, H> ProvingBackendRecorder<'a, S, H>
self.backend.root(),
key,
&mut *self.proof_recorder,
).map_err(map_e)
)
.map_err(map_e)
}
/// Produce proof for a child key query.
pub fn child_storage(
&mut self,
child_info: &ChildInfo,
key: &[u8]
key: &[u8],
) -> Result<Option<Vec<u8>>, String> {
let storage_key = child_info.storage_key();
let root = self.storage(storage_key)?
let root = self
.storage(storage_key)?
.and_then(|r| Decode::decode(&mut &r[..]).ok())
.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>());
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral::new(
self.backend.backend_storage(),
&mut read_overlay,
);
let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay);
let map_e = |e| format!("Trie lookup error: {}", e);
@@ -86,17 +90,15 @@ impl<'a, S, H> ProvingBackendRecorder<'a, S, H>
&eph,
&root.as_ref(),
key,
&mut *self.proof_recorder
).map_err(map_e)
&mut *self.proof_recorder,
)
.map_err(map_e)
}
/// Produce proof for the whole backend.
pub fn record_all_keys(&mut self) {
let mut read_overlay = S::Overlay::default();
let eph = Ephemeral::new(
self.backend.backend_storage(),
&mut read_overlay,
);
let eph = Ephemeral::new(self.backend.backend_storage(), &mut read_overlay);
let mut iter = move || -> Result<(), Box<TrieError<H::Out>>> {
let root = self.backend.root();
@@ -150,13 +152,14 @@ impl<Hash: std::hash::Hash + Eq> ProofRecorder<Hash> {
/// encoded proof.
pub fn estimate_encoded_size(&self) -> usize {
let inner = self.inner.read();
inner.encoded_size
+ codec::Compact(inner.records.len() as u32).encoded_size()
inner.encoded_size + codec::Compact(inner.records.len() as u32).encoded_size()
}
/// Convert into a [`StorageProof`].
pub fn to_storage_proof(&self) -> StorageProof {
let trie_nodes = self.inner.read()
let trie_nodes = self
.inner
.read()
.records
.iter()
.filter_map(|(_k, v)| v.as_ref().map(|v| v.to_vec()))
@@ -175,7 +178,7 @@ impl<Hash: std::hash::Hash + Eq> ProofRecorder<Hash> {
/// Patricia trie-based backend which also tracks all touched storage trie values.
/// These can be sent to remote node and used as a proof of execution.
pub struct ProvingBackend<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> (
pub struct ProvingBackend<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher>(
TrieBackend<ProofRecorderBackend<'a, S, H>, H>,
);
@@ -186,7 +189,8 @@ pub struct ProofRecorderBackend<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hashe
}
impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> ProvingBackend<'a, S, H>
where H::Out: Codec
where
H::Out: Codec,
{
/// Create new proving backend.
pub fn new(backend: &'a TrieBackend<S, H>) -> Self {
@@ -201,10 +205,7 @@ impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> ProvingBackend<'a, S, H>
) -> Self {
let essence = backend.essence();
let root = essence.root().clone();
let recorder = ProofRecorderBackend {
backend: essence.backend_storage(),
proof_recorder,
};
let recorder = ProofRecorderBackend { backend: essence.backend_storage(), proof_recorder };
ProvingBackend(TrieBackend::new(recorder, root))
}
@@ -229,7 +230,7 @@ impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> TrieBackendStorage<H>
fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String> {
if let Some(v) = self.proof_recorder.get(key) {
return Ok(v);
return Ok(v)
}
let backend_value = self.backend.get(key, prefix)?;
@@ -247,10 +248,10 @@ impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> std::fmt::Debug
}
impl<'a, S, H> Backend<H> for ProvingBackend<'a, S, H>
where
S: 'a + TrieBackendStorage<H>,
H: 'a + Hasher,
H::Out: Ord + Codec,
where
S: 'a + TrieBackendStorage<H>,
H: 'a + Hasher,
H::Out: Ord + Codec,
{
type Error = String;
type Transaction = S::Overlay;
@@ -314,7 +315,7 @@ impl<'a, S, H> Backend<H> for ProvingBackend<'a, S, H>
prefix: &[u8],
f: F,
) {
self.0.for_child_keys_with_prefix( child_info, prefix, f)
self.0.for_child_keys_with_prefix(child_info, prefix, f)
}
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
@@ -325,30 +326,32 @@ impl<'a, S, H> Backend<H> for ProvingBackend<'a, S, H>
self.0.keys(prefix)
}
fn child_keys(
&self,
child_info: &ChildInfo,
prefix: &[u8],
) -> Vec<Vec<u8>> {
fn child_keys(&self, child_info: &ChildInfo, prefix: &[u8]) -> Vec<Vec<u8>> {
self.0.child_keys(child_info, prefix)
}
fn storage_root<'b>(
&self,
delta: impl Iterator<Item=(&'b [u8], Option<&'b [u8]>)>,
) -> (H::Out, Self::Transaction) where H::Out: Ord {
delta: impl Iterator<Item = (&'b [u8], Option<&'b [u8]>)>,
) -> (H::Out, Self::Transaction)
where
H::Out: Ord,
{
self.0.storage_root(delta)
}
fn child_storage_root<'b>(
&self,
child_info: &ChildInfo,
delta: impl Iterator<Item=(&'b [u8], Option<&'b [u8]>)>,
) -> (H::Out, bool, Self::Transaction) where H::Out: Ord {
delta: impl Iterator<Item = (&'b [u8], Option<&'b [u8]>)>,
) -> (H::Out, bool, Self::Transaction)
where
H::Out: Ord,
{
self.0.child_storage_root(child_info, delta)
}
fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) { }
fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {}
fn usage_info(&self) -> crate::stats::UsageInfo {
self.0.usage_info()
@@ -375,15 +378,16 @@ where
#[cfg(test)]
mod tests {
use crate::InMemoryBackend;
use crate::trie_backend::tests::test_trie;
use super::*;
use crate::proving_backend::create_proof_check_backend;
use sp_trie::PrefixedMemoryDB;
use crate::{
proving_backend::create_proof_check_backend, trie_backend::tests::test_trie,
InMemoryBackend,
};
use sp_runtime::traits::BlakeTwo256;
use sp_trie::PrefixedMemoryDB;
fn test_proving<'a>(
trie_backend: &'a TrieBackend<PrefixedMemoryDB<BlakeTwo256>,BlakeTwo256>,
trie_backend: &'a TrieBackend<PrefixedMemoryDB<BlakeTwo256>, BlakeTwo256>,
) -> ProvingBackend<'a, PrefixedMemoryDB<BlakeTwo256>, BlakeTwo256> {
ProvingBackend::new(trie_backend)
}
@@ -407,7 +411,7 @@ mod tests {
use sp_core::H256;
let result = create_proof_check_backend::<BlakeTwo256>(
H256::from_low_u64_be(1),
StorageProof::empty()
StorageProof::empty(),
);
assert!(result.is_err());
}
@@ -443,7 +447,8 @@ mod tests {
let proof = proving.extract_proof();
let proof_check = create_proof_check_backend::<BlakeTwo256>(in_memory_root.into(), proof).unwrap();
let proof_check =
create_proof_check_backend::<BlakeTwo256>(in_memory_root.into(), proof).unwrap();
assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]);
}
@@ -455,48 +460,38 @@ mod tests {
let child_info_2 = &child_info_2;
let contents = vec![
(None, (0..64).map(|i| (vec![i], Some(vec![i]))).collect()),
(Some(child_info_1.clone()),
(28..65).map(|i| (vec![i], Some(vec![i]))).collect()),
(Some(child_info_2.clone()),
(10..15).map(|i| (vec![i], Some(vec![i]))).collect()),
(Some(child_info_1.clone()), (28..65).map(|i| (vec![i], Some(vec![i]))).collect()),
(Some(child_info_2.clone()), (10..15).map(|i| (vec![i], Some(vec![i]))).collect()),
];
let in_memory = InMemoryBackend::<BlakeTwo256>::default();
let mut in_memory = in_memory.update(contents);
let child_storage_keys = vec![child_info_1.to_owned(), child_info_2.to_owned()];
let in_memory_root = in_memory.full_storage_root(
std::iter::empty(),
child_storage_keys.iter().map(|k|(k, std::iter::empty()))
).0;
(0..64).for_each(|i| assert_eq!(
in_memory.storage(&[i]).unwrap().unwrap(),
vec![i]
));
(28..65).for_each(|i| assert_eq!(
in_memory.child_storage(child_info_1, &[i]).unwrap().unwrap(),
vec![i]
));
(10..15).for_each(|i| assert_eq!(
in_memory.child_storage(child_info_2, &[i]).unwrap().unwrap(),
vec![i]
));
let in_memory_root = in_memory
.full_storage_root(
std::iter::empty(),
child_storage_keys.iter().map(|k| (k, std::iter::empty())),
)
.0;
(0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i]));
(28..65).for_each(|i| {
assert_eq!(in_memory.child_storage(child_info_1, &[i]).unwrap().unwrap(), vec![i])
});
(10..15).for_each(|i| {
assert_eq!(in_memory.child_storage(child_info_2, &[i]).unwrap().unwrap(), vec![i])
});
let trie = in_memory.as_trie_backend().unwrap();
let trie_root = trie.storage_root(std::iter::empty()).0;
assert_eq!(in_memory_root, trie_root);
(0..64).for_each(|i| assert_eq!(
trie.storage(&[i]).unwrap().unwrap(),
vec![i]
));
(0..64).for_each(|i| assert_eq!(trie.storage(&[i]).unwrap().unwrap(), vec![i]));
let proving = ProvingBackend::new(trie);
assert_eq!(proving.storage(&[42]).unwrap().unwrap(), vec![42]);
let proof = proving.extract_proof();
let proof_check = create_proof_check_backend::<BlakeTwo256>(
in_memory_root.into(),
proof
).unwrap();
let proof_check =
create_proof_check_backend::<BlakeTwo256>(in_memory_root.into(), proof).unwrap();
assert!(proof_check.storage(&[0]).is_err());
assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]);
// note that it is include in root because proof close
@@ -507,14 +502,9 @@ mod tests {
assert_eq!(proving.child_storage(child_info_1, &[64]), Ok(Some(vec![64])));
let proof = proving.extract_proof();
let proof_check = create_proof_check_backend::<BlakeTwo256>(
in_memory_root.into(),
proof
).unwrap();
assert_eq!(
proof_check.child_storage(child_info_1, &[64]).unwrap().unwrap(),
vec![64]
);
let proof_check =
create_proof_check_backend::<BlakeTwo256>(in_memory_root.into(), proof).unwrap();
assert_eq!(proof_check.child_storage(child_info_1, &[64]).unwrap().unwrap(), vec![64]);
}
#[test]
@@ -522,15 +512,14 @@ mod tests {
let trie_backend = test_trie();
let backend = test_proving(&trie_backend);
let check_estimation = |backend: &ProvingBackend<'_, PrefixedMemoryDB<BlakeTwo256>, BlakeTwo256>| {
let storage_proof = backend.extract_proof();
let estimation = backend.0.essence()
.backend_storage()
.proof_recorder
.estimate_encoded_size();
let check_estimation =
|backend: &ProvingBackend<'_, PrefixedMemoryDB<BlakeTwo256>, BlakeTwo256>| {
let storage_proof = backend.extract_proof();
let estimation =
backend.0.essence().backend_storage().proof_recorder.estimate_encoded_size();
assert_eq!(storage_proof.encoded_size(), estimation);
};
assert_eq!(storage_proof.encoded_size(), estimation);
};
assert_eq!(backend.storage(b"key").unwrap(), Some(b"value".to_vec()));
check_estimation(&backend);
@@ -17,17 +17,18 @@
//! Read-only version of Externalities.
use std::{
any::{TypeId, Any},
marker::PhantomData,
};
use crate::{Backend, StorageKey, StorageValue};
use codec::Encode;
use hash_db::Hasher;
use sp_core::{
storage::{ChildInfo, TrackedStorageKey},
traits::Externalities, Blake2Hasher,
traits::Externalities,
Blake2Hasher,
};
use std::{
any::{Any, TypeId},
marker::PhantomData,
};
use codec::Encode;
/// Trait for inspecting state in any backend.
///
@@ -79,39 +80,34 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
}
fn storage(&self, key: &[u8]) -> Option<StorageValue> {
self.backend.storage(key).expect("Backed failed for storage in ReadOnlyExternalities")
self.backend
.storage(key)
.expect("Backed failed for storage in ReadOnlyExternalities")
}
fn storage_hash(&self, key: &[u8]) -> Option<Vec<u8>> {
self.storage(key).map(|v| Blake2Hasher::hash(&v).encode())
}
fn child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageValue> {
self.backend.child_storage(child_info, key).expect("Backed failed for child_storage in ReadOnlyExternalities")
fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageValue> {
self.backend
.child_storage(child_info, key)
.expect("Backed failed for child_storage in ReadOnlyExternalities")
}
fn child_storage_hash(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>> {
fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>> {
self.child_storage(child_info, key).map(|v| Blake2Hasher::hash(&v).encode())
}
fn next_storage_key(&self, key: &[u8]) -> Option<StorageKey> {
self.backend.next_storage_key(key).expect("Backed failed for next_storage_key in ReadOnlyExternalities")
self.backend
.next_storage_key(key)
.expect("Backed failed for next_storage_key in ReadOnlyExternalities")
}
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<StorageKey> {
self.backend.next_child_storage_key(child_info, key)
fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option<StorageKey> {
self.backend
.next_child_storage_key(child_info, key)
.expect("Backed failed for next_child_storage_key in ReadOnlyExternalities")
}
@@ -128,11 +124,7 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
unimplemented!("place_child_storage not supported in ReadOnlyExternalities")
}
fn kill_child_storage(
&mut self,
_child_info: &ChildInfo,
_limit: Option<u32>,
) -> (bool, u32) {
fn kill_child_storage(&mut self, _child_info: &ChildInfo, _limit: Option<u32>) -> (bool, u32) {
unimplemented!("kill_child_storage is not supported in ReadOnlyExternalities")
}
@@ -149,11 +141,7 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
unimplemented!("clear_child_prefix is not supported in ReadOnlyExternalities")
}
fn storage_append(
&mut self,
_key: Vec<u8>,
_value: Vec<u8>,
) {
fn storage_append(&mut self, _key: Vec<u8>, _value: Vec<u8>) {
unimplemented!("storage_append is not supported in ReadOnlyExternalities")
}
@@ -161,10 +149,7 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
unimplemented!("storage_root is not supported in ReadOnlyExternalities")
}
fn child_storage_root(
&mut self,
_child_info: &ChildInfo,
) -> Vec<u8> {
fn child_storage_root(&mut self, _child_info: &ChildInfo) -> Vec<u8> {
unimplemented!("child_storage_root is not supported in ReadOnlyExternalities")
}
@@ -209,7 +194,9 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> Externalities for ReadOnlyExternalities<
}
}
impl<'a, H: Hasher, B: 'a + Backend<H>> sp_externalities::ExtensionStore for ReadOnlyExternalities<'a, H, B> {
impl<'a, H: Hasher, B: 'a + Backend<H>> sp_externalities::ExtensionStore
for ReadOnlyExternalities<'a, H, B>
{
fn extension_by_type_id(&mut self, _type_id: TypeId) -> Option<&mut dyn Any> {
unimplemented!("extension_by_type_id is not supported in ReadOnlyExternalities")
}
@@ -222,7 +209,10 @@ impl<'a, H: Hasher, B: 'a + Backend<H>> sp_externalities::ExtensionStore for Rea
unimplemented!("register_extension_with_type_id is not supported in ReadOnlyExternalities")
}
fn deregister_extension_by_type_id(&mut self, _type_id: TypeId) -> Result<(), sp_externalities::Error> {
fn deregister_extension_by_type_id(
&mut self,
_type_id: TypeId,
) -> Result<(), sp_externalities::Error> {
unimplemented!("deregister_extension_by_type_id is not supported in ReadOnlyExternalities")
}
}
@@ -17,9 +17,9 @@
//! Usage statistics for state db
#[cfg(feature = "std")]
use std::time::{Instant, Duration};
use sp_std::cell::RefCell;
#[cfg(feature = "std")]
use std::time::{Duration, Instant};
/// Measured count of operations and total bytes.
#[derive(Clone, Debug, Default)]
@@ -17,17 +17,19 @@
//! Test implementation for Externalities.
use std::{any::{Any, TypeId}, panic::{AssertUnwindSafe, UnwindSafe}};
use std::{
any::{Any, TypeId},
panic::{AssertUnwindSafe, UnwindSafe},
};
use crate::{
backend::Backend, OverlayedChanges, StorageTransactionCache, ext::Ext, InMemoryBackend,
StorageKey, StorageValue,
backend::Backend,
changes_trie::{
Configuration as ChangesTrieConfiguration,
InMemoryStorage as ChangesTrieInMemoryStorage,
BlockNumber as ChangesTrieBlockNumber,
State as ChangesTrieState,
BlockNumber as ChangesTrieBlockNumber, Configuration as ChangesTrieConfiguration,
InMemoryStorage as ChangesTrieInMemoryStorage, State as ChangesTrieState,
},
ext::Ext,
InMemoryBackend, OverlayedChanges, StorageKey, StorageTransactionCache, StorageValue,
};
use codec::Decode;
@@ -35,13 +37,13 @@ use hash_db::Hasher;
use sp_core::{
offchain::testing::TestPersistentOffchainDB,
storage::{
well_known_keys::{CHANGES_TRIE_CONFIG, CODE, is_child_storage_key},
well_known_keys::{is_child_storage_key, CHANGES_TRIE_CONFIG, CODE},
Storage,
},
traits::TaskExecutorExt,
testing::TaskExecutor,
traits::TaskExecutorExt,
};
use sp_externalities::{Extensions, Extension, ExtensionStore};
use sp_externalities::{Extension, ExtensionStore, Extensions};
/// Simple HashMap-based Externalities impl.
pub struct TestExternalities<H: Hasher, N: ChangesTrieBlockNumber = u64>
@@ -96,7 +98,9 @@ where
/// Create a new instance of `TestExternalities` with code and storage.
pub fn new_with_code(code: &[u8], mut storage: Storage) -> Self {
let mut overlay = OverlayedChanges::default();
let changes_trie_config = storage.top.get(CHANGES_TRIE_CONFIG)
let changes_trie_config = storage
.top
.get(CHANGES_TRIE_CONFIG)
.and_then(|v| Decode::decode(&mut &v[..]).ok());
overlay.set_collect_extrinsics(changes_trie_config.is_some());
@@ -156,17 +160,14 @@ where
/// In contrast to [`commit_all`](Self::commit_all) this will not panic if there are open
/// transactions.
fn as_backend(&self) -> InMemoryBackend<H> {
let top: Vec<_> = self.overlay.changes()
.map(|(k, v)| (k.clone(), v.value().cloned()))
.collect();
let top: Vec<_> =
self.overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned())).collect();
let mut transaction = vec![(None, top)];
for (child_changes, child_info) in self.overlay.children() {
transaction.push((
Some(child_info.clone()),
child_changes
.map(|(k, v)| (k.clone(), v.value().cloned()))
.collect(),
child_changes.map(|(k, v)| (k.clone(), v.value().cloned())).collect(),
))
}
@@ -186,7 +187,8 @@ where
&mut Default::default(),
)?;
self.backend.apply_transaction(changes.transaction_storage_root, changes.transaction);
self.backend
.apply_transaction(changes.transaction_storage_root, changes.transaction);
Ok(())
}
@@ -202,18 +204,21 @@ where
///
/// Returns the result of the given closure, if no panics occured.
/// Otherwise, returns `Err`.
pub fn execute_with_safe<R>(&mut self, f: impl FnOnce() -> R + UnwindSafe) -> Result<R, String> {
pub fn execute_with_safe<R>(
&mut self,
f: impl FnOnce() -> R + UnwindSafe,
) -> Result<R, String> {
let mut ext = AssertUnwindSafe(self.ext());
std::panic::catch_unwind(move ||
std::panic::catch_unwind(move || {
sp_externalities::set_and_run_with_externalities(&mut *ext, f)
).map_err(|e| {
format!("Closure panicked: {:?}", e)
})
.map_err(|e| format!("Closure panicked: {:?}", e))
}
}
impl<H: Hasher, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities<H, N>
where H::Out: Ord + codec::Codec,
where
H::Out: Ord + codec::Codec,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "overlay: {:?}\nbackend: {:?}", self.overlay, self.backend.pairs())
@@ -221,8 +226,8 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> std::fmt::Debug for TestExternalities
}
impl<H: Hasher, N: ChangesTrieBlockNumber> PartialEq for TestExternalities<H, N>
where
H::Out: Ord + 'static + codec::Codec
where
H::Out: Ord + 'static + codec::Codec,
{
/// This doesn't test if they are in the same state, only if they contains the
/// same data at this state
@@ -232,22 +237,25 @@ impl<H: Hasher, N: ChangesTrieBlockNumber> PartialEq for TestExternalities<H, N>
}
impl<H: Hasher, N: ChangesTrieBlockNumber> Default for TestExternalities<H, N>
where
H::Out: Ord + 'static + codec::Codec,
where
H::Out: Ord + 'static + codec::Codec,
{
fn default() -> Self { Self::new(Default::default()) }
fn default() -> Self {
Self::new(Default::default())
}
}
impl<H: Hasher, N: ChangesTrieBlockNumber> From<Storage> for TestExternalities<H, N>
where
H::Out: Ord + 'static + codec::Codec,
where
H::Out: Ord + 'static + codec::Codec,
{
fn from(storage: Storage) -> Self {
Self::new(storage)
}
}
impl<H, N> sp_externalities::ExtensionStore for TestExternalities<H, N> where
impl<H, N> sp_externalities::ExtensionStore for TestExternalities<H, N>
where
H: Hasher,
H::Out: Ord + codec::Codec,
N: ChangesTrieBlockNumber,
@@ -264,7 +272,10 @@ impl<H, N> sp_externalities::ExtensionStore for TestExternalities<H, N> where
self.extensions.register_with_type_id(type_id, extension)
}
fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), sp_externalities::Error> {
fn deregister_extension_by_type_id(
&mut self,
type_id: TypeId,
) -> Result<(), sp_externalities::Error> {
if self.extensions.deregister(type_id) {
Ok(())
} else {
@@ -274,14 +285,13 @@ impl<H, N> sp_externalities::ExtensionStore for TestExternalities<H, N> where
}
impl<H, N> sp_externalities::ExternalitiesExt for TestExternalities<H, N>
where
H: Hasher,
H::Out: Ord + codec::Codec,
N: ChangesTrieBlockNumber,
where
H: Hasher,
H::Out: Ord + codec::Codec,
N: ChangesTrieBlockNumber,
{
fn extension<T: Any + Extension>(&mut self) -> Option<&mut T> {
self.extension_by_type_id(TypeId::of::<T>())
.and_then(<dyn Any>::downcast_mut)
self.extension_by_type_id(TypeId::of::<T>()).and_then(<dyn Any>::downcast_mut)
}
fn register_extension<T: Extension>(&mut self, ext: T) -> Result<(), sp_externalities::Error> {
@@ -296,9 +306,9 @@ impl<H, N> sp_externalities::ExternalitiesExt for TestExternalities<H, N>
#[cfg(test)]
mod tests {
use super::*;
use sp_core::{H256, traits::Externalities, storage::ChildInfo};
use sp_runtime::traits::BlakeTwo256;
use hex_literal::hex;
use sp_core::{storage::ChildInfo, traits::Externalities, H256};
use sp_runtime::traits::BlakeTwo256;
#[test]
fn commit_should_work() {
@@ -307,7 +317,8 @@ mod tests {
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
let root = H256::from(hex!("ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489"));
let root =
H256::from(hex!("ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489"));
assert_eq!(H256::from_slice(ext.storage_root().as_slice()), root);
}
@@ -325,7 +336,7 @@ mod tests {
#[test]
fn check_send() {
fn assert_send<T: Send>() {}
assert_send::<TestExternalities::<BlakeTwo256, u64>>();
assert_send::<TestExternalities<BlakeTwo256, u64>>();
}
#[test]
@@ -17,29 +17,33 @@
//! Trie-based state machine backend.
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};
use sp_core::storage::{ChildInfo, ChildType};
use codec::{Codec, Decode};
use crate::{
StorageKey, StorageValue, Backend,
trie_backend_essence::{TrieBackendEssence, TrieBackendStorage, Ephemeral},
debug,
trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage},
warn, Backend, StorageKey, StorageValue,
};
use codec::{Codec, Decode};
use hash_db::Hasher;
use sp_core::storage::{ChildInfo, ChildType};
use sp_std::{boxed::Box, vec::Vec};
use sp_trie::{
child_delta_trie_root, delta_trie_root, empty_child_trie_root,
trie_types::{Layout, TrieDB, TrieError},
Trie,
};
/// Patricia trie-based backend. Transaction type is an overlay of changes to commit.
pub struct TrieBackend<S: TrieBackendStorage<H>, H: Hasher> {
pub (crate) essence: TrieBackendEssence<S, H>,
pub(crate) essence: TrieBackendEssence<S, H>,
}
impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackend<S, H> where H::Out: Codec {
impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackend<S, H>
where
H::Out: Codec,
{
/// Create new trie-based backend.
pub fn new(storage: S, root: H::Out) -> Self {
TrieBackend {
essence: TrieBackendEssence::new(storage, root),
}
TrieBackend { essence: TrieBackendEssence::new(storage, root) }
}
/// Get backend essence reference.
@@ -74,7 +78,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> sp_std::fmt::Debug for TrieBackend<S,
}
}
impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H>
where
H::Out: Ord + Codec,
{
type Error = crate::DefaultError;
@@ -121,7 +126,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
f: F,
allow_missing: bool,
) -> Result<bool, Self::Error> {
self.essence.apply_to_key_values_while(child_info, prefix, start_at, f, allow_missing)
self.essence
.apply_to_key_values_while(child_info, prefix, start_at, f, allow_missing)
}
fn apply_to_keys_while<F: FnMut(&[u8]) -> bool>(
@@ -159,7 +165,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
Err(e) => {
debug!(target: "trie", "Error extracting trie values: {}", e);
Vec::new()
}
},
}
}
@@ -177,21 +183,23 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
Ok(v)
};
collect_all().map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e)).unwrap_or_default()
collect_all()
.map_err(|e| debug!(target: "trie", "Error extracting trie keys: {}", e))
.unwrap_or_default()
}
fn storage_root<'a>(
&self,
delta: impl Iterator<Item=(&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, Self::Transaction) where H::Out: Ord {
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, Self::Transaction)
where
H::Out: Ord,
{
let mut write_overlay = S::Overlay::default();
let mut root = *self.essence.root();
{
let mut eph = Ephemeral::new(
self.essence.backend_storage(),
&mut write_overlay,
);
let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay);
match delta_trie_root::<Layout<H>, _, _, _, _, _>(&mut eph, root, delta) {
Ok(ret) => root = ret,
@@ -205,17 +213,21 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
fn child_storage_root<'a>(
&self,
child_info: &ChildInfo,
delta: impl Iterator<Item=(&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, bool, Self::Transaction) where H::Out: Ord {
delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
) -> (H::Out, bool, Self::Transaction)
where
H::Out: Ord,
{
let default_root = match child_info.child_type() {
ChildType::ParentKeyId => empty_child_trie_root::<Layout<H>>()
ChildType::ParentKeyId => empty_child_trie_root::<Layout<H>>(),
};
let mut write_overlay = S::Overlay::default();
let prefixed_storage_key = child_info.prefixed_storage_key();
let mut root = match self.storage(prefixed_storage_key.as_slice()) {
Ok(value) =>
value.and_then(|r| Decode::decode(&mut &r[..]).ok()).unwrap_or_else(|| default_root.clone()),
Ok(value) => value
.and_then(|r| Decode::decode(&mut &r[..]).ok())
.unwrap_or_else(|| default_root.clone()),
Err(e) => {
warn!(target: "trie", "Failed to read child storage root: {}", e);
default_root.clone()
@@ -223,10 +235,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
};
{
let mut eph = Ephemeral::new(
self.essence.backend_storage(),
&mut write_overlay,
);
let mut eph = Ephemeral::new(self.essence.backend_storage(), &mut write_overlay);
match child_delta_trie_root::<Layout<H>, _, _, _, _, _, _>(
child_info.keyspace(),
@@ -248,7 +257,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
Some(self)
}
fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) { }
fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {}
fn usage_info(&self) -> crate::UsageInfo {
crate::UsageInfo::empty()
@@ -261,12 +270,12 @@ impl<S: TrieBackendStorage<H>, H: Hasher> Backend<H> for TrieBackend<S, H> where
#[cfg(test)]
pub mod tests {
use std::{collections::HashSet, iter};
use sp_core::H256;
use codec::Encode;
use sp_trie::{TrieMut, PrefixedMemoryDB, trie_types::TrieDBMut, KeySpacedDBMut};
use sp_runtime::traits::BlakeTwo256;
use super::*;
use codec::Encode;
use sp_core::H256;
use sp_runtime::traits::BlakeTwo256;
use sp_trie::{trie_types::TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut};
use std::{collections::HashSet, iter};
const CHILD_KEY_1: &[u8] = b"sub1";
@@ -312,7 +321,9 @@ pub mod tests {
fn read_from_child_storage_returns_some() {
let test_trie = test_trie();
assert_eq!(
test_trie.child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3").unwrap(),
test_trie
.child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3")
.unwrap(),
Some(vec![142u8]),
);
}
@@ -332,7 +343,9 @@ pub mod tests {
assert!(TrieBackend::<PrefixedMemoryDB<BlakeTwo256>, BlakeTwo256>::new(
PrefixedMemoryDB::default(),
Default::default(),
).pairs().is_empty());
)
.pairs()
.is_empty());
}
#[test]
@@ -347,9 +360,8 @@ pub mod tests {
#[test]
fn storage_root_transaction_is_non_empty() {
let (new_root, mut tx) = test_trie().storage_root(
iter::once((&b"new-key"[..], Some(&b"new-value"[..]))),
);
let (new_root, mut tx) =
test_trie().storage_root(iter::once((&b"new-key"[..], Some(&b"new-value"[..]))));
assert!(!tx.drain().is_empty());
assert!(new_root != test_trie().storage_root(iter::empty()).0);
}
@@ -18,24 +18,24 @@
//! Trie-based state machine backend essence used to read values
//! from storage.
use crate::{backend::Consolidate, debug, warn, StorageKey, StorageValue};
use codec::Encode;
use hash_db::{self, Hasher, Prefix};
use sp_core::storage::ChildInfo;
use sp_std::{boxed::Box, ops::Deref, vec::Vec};
use sp_trie::{
empty_child_trie_root, read_child_trie_value, read_trie_value,
trie_types::{Layout, TrieDB, TrieError},
DBValue, KeySpacedDB, MemoryDB, PrefixedMemoryDB, Trie, TrieDBIterator,
};
#[cfg(feature = "std")]
use std::sync::Arc;
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,
KeySpacedDB, TrieDBIterator};
use sp_trie::trie_types::{TrieDB, TrieError, Layout};
use crate::{backend::Consolidate, StorageKey, StorageValue};
use sp_core::storage::ChildInfo;
use codec::Encode;
#[cfg(not(feature = "std"))]
macro_rules! format {
($($arg:tt)+) => (
($($arg:tt)+) => {
crate::DefaultError
);
};
}
type Result<V> = sp_std::result::Result<V, crate::DefaultError>;
@@ -53,14 +53,13 @@ pub struct TrieBackendEssence<S: TrieBackendStorage<H>, H: Hasher> {
empty: H::Out,
}
impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out: Encode {
impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H>
where
H::Out: Encode,
{
/// Create new trie-based backend.
pub fn new(storage: S, root: H::Out) -> Self {
TrieBackendEssence {
storage,
root,
empty: H::hash(&[0u8]),
}
TrieBackendEssence { storage, root, empty: H::hash(&[0u8]) }
}
/// Get backend storage reference.
@@ -114,7 +113,7 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
let mut hash = H::Out::default();
if child_root.len() != hash.as_ref().len() {
return Err(format!("Invalid child storage hash at {:?}", child_info.storage_key()));
return Err(format!("Invalid child storage hash at {:?}", child_info.storage_key()))
}
// note: child_root and hash must be same size, panics otherwise.
hash.as_mut().copy_from_slice(&child_root[..]);
@@ -138,10 +137,9 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
dyn_eph = self;
}
let trie = TrieDB::<H>::new(dyn_eph, root)
.map_err(|e| format!("TrieDB creation error: {}", e))?;
let mut iter = trie.iter()
.map_err(|e| format!("TrieDB iteration error: {}", e))?;
let trie =
TrieDB::<H>::new(dyn_eph, root).map_err(|e| format!("TrieDB creation error: {}", e))?;
let mut iter = trie.iter().map_err(|e| format!("TrieDB iteration error: {}", e))?;
// The key just after the one given in input, basically `key++0`.
// Note: We are sure this is the next key if:
@@ -157,8 +155,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
let next_element = iter.next();
let next_key = if let Some(next_element) = next_element {
let (next_key, _) = next_element
.map_err(|e| format!("TrieDB iterator next error: {}", e))?;
let (next_key, _) =
next_element.map_err(|e| format!("TrieDB iterator next error: {}", e))?;
Some(next_key)
} else {
None
@@ -180,7 +178,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
child_info: &ChildInfo,
key: &[u8],
) -> Result<Option<StorageValue>> {
let root = self.child_root(child_info)?
let root = self
.child_root(child_info)?
.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode());
let map_e = |e| format!("Trie lookup error: {}", e);
@@ -210,20 +209,13 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
&child_root
} else {
return Ok(true);
return Ok(true)
}
} else {
&self.root
};
self.trie_iter_inner(
&root,
prefix,
f,
child_info,
start_at,
allow_missing_nodes,
)
self.trie_iter_inner(&root, prefix, f, child_info, start_at, allow_missing_nodes)
}
/// Retrieve all entries keys of a storage and call `f` for each of those keys.
@@ -240,8 +232,8 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode()),
Err(e) => {
debug!(target: "trie", "Error while iterating child storage: {}", e);
return;
}
return
},
};
child_root.as_mut().copy_from_slice(&root_vec);
&child_root
@@ -249,7 +241,17 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
&self.root
};
let _ = self.trie_iter_inner(root, prefix, |k, _v| { f(&k); true}, child_info, None, false);
let _ = self.trie_iter_inner(
root,
prefix,
|k, _v| {
f(&k);
true
},
child_info,
None,
false,
);
}
/// Execute given closure for all keys starting with prefix.
@@ -263,17 +265,37 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode()),
Err(e) => {
debug!(target: "trie", "Error while iterating child storage: {}", e);
return;
}
return
},
};
let mut root = H::Out::default();
root.as_mut().copy_from_slice(&root_vec);
let _ = self.trie_iter_inner(&root, Some(prefix), |k, _v| { f(&k); true }, Some(child_info), None, false);
let _ = self.trie_iter_inner(
&root,
Some(prefix),
|k, _v| {
f(&k);
true
},
Some(child_info),
None,
false,
);
}
/// Execute given closure for all keys starting with prefix.
pub fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], mut f: F) {
let _ = self.trie_iter_inner(&self.root, Some(prefix), |k, _v| { f(&k); true }, None, None, false);
let _ = self.trie_iter_inner(
&self.root,
Some(prefix),
|k, _v| {
f(&k);
true
},
None,
None,
false,
);
}
fn trie_iter_inner<F: FnMut(Vec<u8>, Vec<u8>) -> bool>(
@@ -315,14 +337,25 @@ impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out:
};
match result {
Ok(completed) => Ok(completed),
Err(e) if matches!(*e, TrieError::IncompleteDatabase(_)) && allow_missing_nodes => Ok(false),
Err(e) if matches!(*e, TrieError::IncompleteDatabase(_)) && allow_missing_nodes =>
Ok(false),
Err(e) => Err(format!("TrieDB iteration error: {}", e)),
}
}
/// Execute given closure for all key and values starting with prefix.
pub fn for_key_values_with_prefix<F: FnMut(&[u8], &[u8])>(&self, prefix: &[u8], mut f: F) {
let _ = self.trie_iter_inner(&self.root, Some(prefix), |k, v| {f(&k, &v); true}, None, None, false);
let _ = self.trie_iter_inner(
&self.root,
Some(prefix),
|k, v| {
f(&k, &v);
true
},
None,
None,
false,
);
}
}
@@ -334,16 +367,17 @@ pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> {
impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> hash_db::AsHashDB<H, DBValue>
for Ephemeral<'a, S, H>
{
fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB<H, DBValue> + 'b) {
self
}
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, DBValue> + 'b) {
self
}
}
impl<'a, S: TrieBackendStorage<H>, H: Hasher> Ephemeral<'a, S, H> {
pub fn new(storage: &'a S, overlay: &'a mut S::Overlay) -> Self {
Ephemeral {
storage,
overlay,
}
Ephemeral { storage, overlay }
}
}
@@ -431,13 +465,15 @@ impl<H: Hasher> TrieBackendStorage<H> for MemoryDB<H> {
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::AsHashDB<H, DBValue>
for TrieBackendEssence<S, H>
{
fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, DBValue> + 'b) { self }
fn as_hash_db<'b>(&'b self) -> &'b (dyn hash_db::HashDB<H, DBValue> + 'b) {
self
}
fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn hash_db::HashDB<H, DBValue> + 'b) {
self
}
}
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::HashDB<H, DBValue>
for TrieBackendEssence<S, H>
{
impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::HashDB<H, DBValue> for TrieBackendEssence<S, H> {
fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
if *key == self.empty {
return Some([0u8].to_vec())
@@ -480,12 +516,11 @@ impl<S: TrieBackendStorage<H>, H: Hasher> hash_db::HashDBRef<H, DBValue>
}
}
#[cfg(test)]
mod test {
use sp_core::{Blake2Hasher, H256};
use sp_trie::{TrieMut, PrefixedMemoryDB, trie_types::TrieDBMut, KeySpacedDBMut};
use super::*;
use sp_core::{Blake2Hasher, H256};
use sp_trie::{trie_types::TrieDBMut, KeySpacedDBMut, PrefixedMemoryDB, TrieMut};
#[test]
fn next_storage_key_and_next_child_storage_key_work() {
@@ -529,20 +564,10 @@ mod test {
let mdb = essence_1.into_storage();
let essence_2 = TrieBackendEssence::new(mdb, root_2);
assert_eq!(
essence_2.next_child_storage_key(child_info, b"2"), Ok(Some(b"3".to_vec()))
);
assert_eq!(
essence_2.next_child_storage_key(child_info, b"3"), Ok(Some(b"4".to_vec()))
);
assert_eq!(
essence_2.next_child_storage_key(child_info, b"4"), Ok(Some(b"6".to_vec()))
);
assert_eq!(
essence_2.next_child_storage_key(child_info, b"5"), Ok(Some(b"6".to_vec()))
);
assert_eq!(
essence_2.next_child_storage_key(child_info, b"6"), Ok(None)
);
assert_eq!(essence_2.next_child_storage_key(child_info, b"2"), Ok(Some(b"3".to_vec())));
assert_eq!(essence_2.next_child_storage_key(child_info, b"3"), Ok(Some(b"4".to_vec())));
assert_eq!(essence_2.next_child_storage_key(child_info, b"4"), Ok(Some(b"6".to_vec())));
assert_eq!(essence_2.next_child_storage_key(child_info, b"5"), Ok(Some(b"6".to_vec())));
assert_eq!(essence_2.next_child_storage_key(child_info, b"6"), Ok(None));
}
}