// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
//! State machine in memory backend.
use crate::{
StorageKey, StorageValue, StorageCollection,
trie_backend::TrieBackend,
};
use std::{collections::{BTreeMap, HashMap}};
use hash_db::Hasher;
use sp_trie::{
MemoryDB, TrieMut,
trie_types::TrieDBMut,
};
use codec::Codec;
use sp_core::storage::{ChildInfo, Storage};
/// Insert input pairs into memory db.
fn insert_into_memory_db(mut root: H::Out, mdb: &mut MemoryDB, input: I) -> H::Out
where
H: Hasher,
I: IntoIterator)>,
{
{
let mut trie = if root == Default::default() {
TrieDBMut::::new(mdb, &mut root)
} else {
TrieDBMut::::from_existing(mdb, &mut root).unwrap()
};
for (key, value) in input {
if let Err(e) = match value {
Some(value) => {
trie.insert(&key, &value)
},
None => {
trie.remove(&key)
},
} {
panic!("Failed to write to trie: {}", e);
}
}
trie.commit();
}
root
}
/// Create a new empty instance of in-memory backend.
pub fn new_in_mem() -> TrieBackend, H>
where
H::Out: Codec + Ord,
{
let db = MemoryDB::default();
let mut backend = TrieBackend::new(db, Default::default());
backend.insert(std::iter::empty());
backend
}
impl TrieBackend, H>
where
H::Out: Codec + Ord,
{
/// Copy the state, with applied updates
pub fn update<
T: IntoIterator, StorageCollection)>
>(
&self,
changes: T,
) -> Self {
let mut clone = self.clone();
clone.insert(changes);
clone
}
/// Insert values into backend trie.
pub fn insert<
T: IntoIterator, StorageCollection)>
>(
&mut self,
changes: T,
) {
let mut new_child_roots = Vec::new();
let mut root_map = None;
let root = self.root().clone();
for (child_info, map) in changes {
if let Some(child_info) = child_info.as_ref() {
let prefix_storage_key = child_info.prefixed_storage_key();
let ch = insert_into_memory_db::(root, self.backend_storage_mut(), map.clone().into_iter());
new_child_roots.push((prefix_storage_key.into_inner(), Some(ch.as_ref().into())));
} else {
root_map = Some(map);
}
}
let root = match root_map {
Some(map) => insert_into_memory_db::(
root,
self.backend_storage_mut(),
map.into_iter().chain(new_child_roots.into_iter()),
),
None => insert_into_memory_db::(
root,
self.backend_storage_mut(),
new_child_roots.into_iter(),
),
};
self.essence.set_root(root);
}
/// Merge trie nodes into this backend.
pub fn update_backend(&self, root: H::Out, changes: MemoryDB) -> Self {
let mut clone = self.backend_storage().clone();
clone.consolidate(changes);
Self::new(clone, root)
}
/// Compare with another in-memory backend.
pub fn eq(&self, other: &Self) -> bool {
self.root() == other.root()
}
}
impl Clone for TrieBackend, H>
where
H::Out: Codec + Ord,
{
fn clone(&self) -> Self {
TrieBackend::new(self.backend_storage().clone(), self.root().clone())
}
}
impl Default for TrieBackend, H>
where
H::Out: Codec + Ord,
{
fn default() -> Self {
new_in_mem()
}
}
impl From, BTreeMap>>
for TrieBackend, H>
where
H::Out: Codec + Ord,
{
fn from(inner: HashMap