mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 06:27:58 +00:00
bc2e5e1fe2
First in a series of PRs that reduces our use of sp-std with a view to deprecating it. This is just looking at /substrate and moving some of the references from `sp-std` to `core`. These particular changes should be uncontroversial. Where macros are used `::core` should be used to remove any ambiguity. part of https://github.com/paritytech/polkadot-sdk/issues/2101
227 lines
6.6 KiB
Rust
227 lines
6.6 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! State machine in memory backend.
|
|
|
|
use crate::{
|
|
backend::Backend, trie_backend::TrieBackend, StorageCollection, StorageKey, StorageValue,
|
|
TrieBackendBuilder,
|
|
};
|
|
use codec::Codec;
|
|
use hash_db::Hasher;
|
|
use sp_core::storage::{ChildInfo, StateVersion, Storage};
|
|
use sp_trie::{empty_trie_root, LayoutV1, PrefixedMemoryDB};
|
|
use std::collections::{BTreeMap, HashMap};
|
|
|
|
/// Create a new empty instance of in-memory backend.
|
|
pub fn new_in_mem<H>() -> TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H: Hasher,
|
|
H::Out: Codec + Ord,
|
|
{
|
|
// V1 is same as V0 for an empty trie.
|
|
TrieBackendBuilder::new(Default::default(), empty_trie_root::<LayoutV1<H>>()).build()
|
|
}
|
|
|
|
impl<H: Hasher> TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
/// Copy the state, with applied updates
|
|
pub fn update<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
|
|
&self,
|
|
changes: T,
|
|
state_version: StateVersion,
|
|
) -> Self {
|
|
let mut clone = self.clone();
|
|
clone.insert(changes, state_version);
|
|
clone
|
|
}
|
|
|
|
/// Insert values into backend trie.
|
|
pub fn insert<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
|
|
&mut self,
|
|
changes: T,
|
|
state_version: StateVersion,
|
|
) {
|
|
let (top, child) = changes.into_iter().partition::<Vec<_>, _>(|v| v.0.is_none());
|
|
let (root, transaction) = self.full_storage_root(
|
|
top.iter().flat_map(|(_, v)| v).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()))))
|
|
}),
|
|
state_version,
|
|
);
|
|
|
|
self.apply_transaction(root, transaction);
|
|
}
|
|
|
|
/// Merge trie nodes into this backend.
|
|
pub fn update_backend(&self, root: H::Out, changes: PrefixedMemoryDB<H>) -> Self {
|
|
let mut clone = self.backend_storage().clone();
|
|
clone.consolidate(changes);
|
|
TrieBackendBuilder::new(clone, root).build()
|
|
}
|
|
|
|
/// Apply the given transaction to this backend and set the root to the given value.
|
|
pub fn apply_transaction(&mut self, root: H::Out, transaction: PrefixedMemoryDB<H>) {
|
|
let mut storage = core::mem::take(self).into_storage();
|
|
|
|
storage.consolidate(transaction);
|
|
*self = TrieBackendBuilder::new(storage, root).build();
|
|
}
|
|
|
|
/// Compare with another in-memory backend.
|
|
pub fn eq(&self, other: &Self) -> bool {
|
|
self.root() == other.root()
|
|
}
|
|
}
|
|
|
|
impl<H: Hasher> Clone for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn clone(&self) -> Self {
|
|
TrieBackendBuilder::new(self.backend_storage().clone(), *self.root()).build()
|
|
}
|
|
}
|
|
|
|
impl<H> Default for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H: Hasher,
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn default() -> Self {
|
|
new_in_mem()
|
|
}
|
|
}
|
|
|
|
impl<H: Hasher> From<(HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>, StateVersion)>
|
|
for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn from(
|
|
(inner, state_version): (
|
|
HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>,
|
|
StateVersion,
|
|
),
|
|
) -> 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())),
|
|
state_version,
|
|
);
|
|
backend
|
|
}
|
|
}
|
|
|
|
impl<H: Hasher> From<(Storage, StateVersion)> for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn from((inners, state_version): (Storage, StateVersion)) -> Self {
|
|
let mut inner: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>> = inners
|
|
.children_default
|
|
.into_values()
|
|
.map(|c| (Some(c.child_info), c.data))
|
|
.collect();
|
|
inner.insert(None, inners.top);
|
|
(inner, state_version).into()
|
|
}
|
|
}
|
|
|
|
impl<H: Hasher> From<(BTreeMap<StorageKey, StorageValue>, StateVersion)>
|
|
for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn from((inner, state_version): (BTreeMap<StorageKey, StorageValue>, StateVersion)) -> Self {
|
|
let mut expanded = HashMap::new();
|
|
expanded.insert(None, inner);
|
|
(expanded, state_version).into()
|
|
}
|
|
}
|
|
|
|
impl<H: Hasher> From<(Vec<(Option<ChildInfo>, StorageCollection)>, StateVersion)>
|
|
for TrieBackend<PrefixedMemoryDB<H>, H>
|
|
where
|
|
H::Out: Codec + Ord,
|
|
{
|
|
fn from(
|
|
(inner, state_version): (Vec<(Option<ChildInfo>, StorageCollection)>, StateVersion),
|
|
) -> 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 {
|
|
if let Some(value) = value {
|
|
entry.insert(key, value);
|
|
}
|
|
}
|
|
}
|
|
(expanded, state_version).into()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::backend::{AsTrieBackend, Backend};
|
|
use sp_core::storage::StateVersion;
|
|
use sp_runtime::traits::BlakeTwo256;
|
|
|
|
/// Assert in memory backend with only child trie keys works as trie backend.
|
|
#[test]
|
|
fn in_memory_with_child_trie_only() {
|
|
let state_version = StateVersion::default();
|
|
let storage = new_in_mem::<BlakeTwo256>();
|
|
let child_info = ChildInfo::new_default(b"1");
|
|
let child_info = &child_info;
|
|
let storage = storage.update(
|
|
vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])],
|
|
state_version,
|
|
);
|
|
let trie_backend = storage.as_trie_backend();
|
|
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());
|
|
}
|
|
|
|
#[test]
|
|
fn insert_multiple_times_child_data_works() {
|
|
let state_version = StateVersion::default();
|
|
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()))])],
|
|
state_version,
|
|
);
|
|
storage.insert(
|
|
vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])],
|
|
state_version,
|
|
);
|
|
|
|
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())));
|
|
}
|
|
}
|