mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 01:07:57 +00:00
Introduce prefixed storage with enumeration (#4185)
* Introduce storage_next allowing iteration. (without childtries) * Implement prefixed storage * impl cache in client_storage_cache (needs test) * switch overlay change to btreemap * Revert "impl cache in client_storage_cache" This reverts commit c91a4848916eba87184b3dc4722cea81aec9339d. the storage cache cannot be used this way * Revert "Implement prefixed storage" This reverts commit 4931088126a427082d7310ed7e83b8eea966bc20. * Impl StoragePrefixedMap for all map storages * remove comment * Move all overlays to BTreeMap * btreemap iteration improvment * impl for child tries * impl tests for childs * fix * remove cache comment * Fix grumble
This commit is contained in:
committed by
Bastian Köcher
parent
fb1eb9d9e4
commit
e5b6935c2a
@@ -16,7 +16,7 @@
|
||||
|
||||
//! State machine backends. These manage the code and storage of contracts.
|
||||
|
||||
use std::{error, fmt, cmp::Ord, collections::HashMap, marker::PhantomData};
|
||||
use std::{error, fmt, cmp::Ord, collections::{HashMap, BTreeMap}, marker::PhantomData, ops};
|
||||
use log::warn;
|
||||
use hash_db::Hasher;
|
||||
use crate::trie_backend::TrieBackend;
|
||||
@@ -67,6 +67,16 @@ pub trait Backend<H: Hasher>: std::fmt::Debug {
|
||||
Ok(self.child_storage(storage_key, key)?.is_some())
|
||||
}
|
||||
|
||||
/// Return the next key in storage in lexicographic order or `None` if there is no value.
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
|
||||
/// Return the next key in child storage in lexicographic order or `None` if there is no value.
|
||||
fn next_child_storage_key(
|
||||
&self,
|
||||
storage_key: &[u8],
|
||||
key: &[u8]
|
||||
) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
|
||||
/// Retrieve all entries keys of child storage and call `f` for each of those keys.
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F);
|
||||
|
||||
@@ -171,6 +181,14 @@ impl<'a, T: Backend<H>, H: Hasher> Backend<H> for &'a T {
|
||||
(*self).child_storage(storage_key, key)
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
(*self).next_storage_key(key)
|
||||
}
|
||||
|
||||
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
(*self).next_child_storage_key(storage_key, key)
|
||||
}
|
||||
|
||||
fn for_keys_in_child_storage<F: FnMut(&[u8])>(&self, storage_key: &[u8], f: F) {
|
||||
(*self).for_keys_in_child_storage(storage_key, f)
|
||||
}
|
||||
@@ -250,7 +268,7 @@ impl error::Error for Void {
|
||||
/// In-memory backend. Fully recomputes tries each time `as_trie_backend` is called but useful for
|
||||
/// tests and proof checking.
|
||||
pub struct InMemory<H: Hasher> {
|
||||
inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>,
|
||||
inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||
// This field is only needed for returning reference in `as_trie_backend`.
|
||||
trie: Option<TrieBackend<MemoryDB<H>, H>>,
|
||||
_hasher: PhantomData<H>,
|
||||
@@ -291,7 +309,7 @@ impl<H: Hasher> PartialEq for InMemory<H> {
|
||||
impl<H: Hasher> InMemory<H> where H::Out: Codec {
|
||||
/// Copy the state, with applied updates
|
||||
pub fn update(&self, changes: <Self as Backend<H>>::Transaction) -> Self {
|
||||
let mut inner: HashMap<_, _> = self.inner.clone();
|
||||
let mut inner = self.inner.clone();
|
||||
for (storage_key, key, val) in changes {
|
||||
match val {
|
||||
Some(v) => { inner.entry(storage_key).or_default().insert(key, v); },
|
||||
@@ -303,8 +321,8 @@ impl<H: Hasher> InMemory<H> where H::Out: Codec {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hasher> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
|
||||
fn from(inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>) -> Self {
|
||||
impl<H: Hasher> From<HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>> for InMemory<H> {
|
||||
fn from(inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>) -> Self {
|
||||
InMemory {
|
||||
inner: inner,
|
||||
trie: None,
|
||||
@@ -314,14 +332,14 @@ impl<H: Hasher> From<HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>> for In
|
||||
}
|
||||
|
||||
impl<H: Hasher> From<(
|
||||
HashMap<Vec<u8>, Vec<u8>>,
|
||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
||||
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||
)> for InMemory<H> {
|
||||
fn from(inners: (
|
||||
HashMap<Vec<u8>, Vec<u8>>,
|
||||
HashMap<Vec<u8>, HashMap<Vec<u8>, Vec<u8>>>,
|
||||
BTreeMap<Vec<u8>, Vec<u8>>,
|
||||
HashMap<Vec<u8>, BTreeMap<Vec<u8>, Vec<u8>>>,
|
||||
)) -> Self {
|
||||
let mut inner: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>>
|
||||
let mut inner: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>>
|
||||
= inners.1.into_iter().map(|(k, v)| (Some(k), v)).collect();
|
||||
inner.insert(None, inners.0);
|
||||
InMemory {
|
||||
@@ -332,8 +350,8 @@ impl<H: Hasher> From<(
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hasher> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
||||
fn from(inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
|
||||
impl<H: Hasher> From<BTreeMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
||||
fn from(inner: BTreeMap<Vec<u8>, Vec<u8>>) -> Self {
|
||||
let mut expanded = HashMap::new();
|
||||
expanded.insert(None, inner);
|
||||
InMemory {
|
||||
@@ -346,7 +364,7 @@ impl<H: Hasher> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H> {
|
||||
|
||||
impl<H: Hasher> From<Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>> for InMemory<H> {
|
||||
fn from(inner: Vec<(Option<Vec<u8>>, Vec<u8>, Option<Vec<u8>>)>) -> Self {
|
||||
let mut expanded: HashMap<Option<Vec<u8>>, HashMap<Vec<u8>, Vec<u8>>> = HashMap::new();
|
||||
let mut expanded: HashMap<Option<Vec<u8>>, BTreeMap<Vec<u8>, Vec<u8>>> = HashMap::new();
|
||||
for (child_key, key, value) in inner {
|
||||
if let Some(value) = value {
|
||||
expanded.entry(child_key).or_default().insert(key, value);
|
||||
@@ -380,6 +398,22 @@ impl<H: Hasher> Backend<H> for InMemory<H> where H::Out: Codec {
|
||||
Ok(self.inner.get(&None).map(|map| map.get(key).is_some()).unwrap_or(false))
|
||||
}
|
||||
|
||||
fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||
let next_key = self.inner.get(&None)
|
||||
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||
|
||||
Ok(next_key)
|
||||
}
|
||||
|
||||
fn next_child_storage_key(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
let range = (ops::Bound::Excluded(key), ops::Bound::Unbounded);
|
||||
let next_key = self.inner.get(&Some(storage_key.to_vec()))
|
||||
.and_then(|map| map.range::<[u8], _>(range).next().map(|(k, _)| k).cloned());
|
||||
|
||||
Ok(next_key)
|
||||
}
|
||||
|
||||
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], f: F) {
|
||||
self.inner.get(&None).map(|map| map.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user