1use crate::{
21 backend::Backend, trie_backend::TrieBackend, StorageCollection, StorageKey, StorageValue,
22 TrieBackendBuilder,
23};
24use codec::Codec;
25use hash_db::Hasher;
26use sp_core::storage::{ChildInfo, StateVersion, Storage};
27use sp_trie::{empty_trie_root, LayoutV1, PrefixedMemoryDB};
28use std::collections::{BTreeMap, HashMap};
29
30pub fn new_in_mem<H>() -> TrieBackend<PrefixedMemoryDB<H>, H>
32where
33 H: Hasher,
34 H::Out: Codec + Ord,
35{
36 TrieBackendBuilder::new(Default::default(), empty_trie_root::<LayoutV1<H>>()).build()
38}
39
40impl<H: Hasher> TrieBackend<PrefixedMemoryDB<H>, H>
41where
42 H::Out: Codec + Ord,
43{
44 pub fn update<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
46 &self,
47 changes: T,
48 state_version: StateVersion,
49 ) -> Self {
50 let mut clone = self.clone();
51 clone.insert(changes, state_version);
52 clone
53 }
54
55 pub fn insert<T: IntoIterator<Item = (Option<ChildInfo>, StorageCollection)>>(
57 &mut self,
58 changes: T,
59 state_version: StateVersion,
60 ) {
61 let (top, child) = changes.into_iter().partition::<Vec<_>, _>(|v| v.0.is_none());
62 let (root, transaction) = self.full_storage_root(
63 top.iter().flat_map(|(_, v)| v).map(|(k, v)| (&k[..], v.as_deref())),
64 child.iter().filter_map(|v| {
65 v.0.as_ref().map(|c| (c, v.1.iter().map(|(k, v)| (&k[..], v.as_deref()))))
66 }),
67 state_version,
68 );
69
70 self.apply_transaction(root, transaction);
71 }
72
73 pub fn update_backend(&self, root: H::Out, changes: PrefixedMemoryDB<H>) -> Self {
75 let mut clone = self.backend_storage().clone();
76 clone.consolidate(changes);
77 TrieBackendBuilder::new(clone, root).build()
78 }
79
80 pub fn apply_transaction(&mut self, root: H::Out, transaction: PrefixedMemoryDB<H>) {
82 let mut storage = core::mem::take(self).into_storage();
83
84 storage.consolidate(transaction);
85 *self = TrieBackendBuilder::new(storage, root).build();
86 }
87
88 pub fn eq(&self, other: &Self) -> bool {
90 self.root() == other.root()
91 }
92}
93
94impl<H: Hasher> Clone for TrieBackend<PrefixedMemoryDB<H>, H>
95where
96 H::Out: Codec + Ord,
97{
98 fn clone(&self) -> Self {
99 TrieBackendBuilder::new(self.backend_storage().clone(), *self.root()).build()
100 }
101}
102
103impl<H> Default for TrieBackend<PrefixedMemoryDB<H>, H>
104where
105 H: Hasher,
106 H::Out: Codec + Ord,
107{
108 fn default() -> Self {
109 new_in_mem()
110 }
111}
112
113impl<H: Hasher> From<(HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>, StateVersion)>
114 for TrieBackend<PrefixedMemoryDB<H>, H>
115where
116 H::Out: Codec + Ord,
117{
118 fn from(
119 (inner, state_version): (
120 HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>>,
121 StateVersion,
122 ),
123 ) -> Self {
124 let mut backend = new_in_mem();
125 backend.insert(
126 inner
127 .into_iter()
128 .map(|(k, m)| (k, m.into_iter().map(|(k, v)| (k, Some(v))).collect())),
129 state_version,
130 );
131 backend
132 }
133}
134
135#[cfg(feature = "std")]
136impl<H: Hasher> From<(Storage, StateVersion)> for TrieBackend<PrefixedMemoryDB<H>, H>
137where
138 H::Out: Codec + Ord,
139{
140 fn from((inners, state_version): (Storage, StateVersion)) -> Self {
141 let mut inner: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>> = inners
142 .children_default
143 .into_values()
144 .map(|c| (Some(c.child_info), c.data))
145 .collect();
146 inner.insert(None, inners.top);
147 (inner, state_version).into()
148 }
149}
150
151impl<H: Hasher> From<(BTreeMap<StorageKey, StorageValue>, StateVersion)>
152 for TrieBackend<PrefixedMemoryDB<H>, H>
153where
154 H::Out: Codec + Ord,
155{
156 fn from((inner, state_version): (BTreeMap<StorageKey, StorageValue>, StateVersion)) -> Self {
157 let mut expanded = HashMap::new();
158 expanded.insert(None, inner);
159 (expanded, state_version).into()
160 }
161}
162
163impl<H: Hasher> From<(Vec<(Option<ChildInfo>, StorageCollection)>, StateVersion)>
164 for TrieBackend<PrefixedMemoryDB<H>, H>
165where
166 H::Out: Codec + Ord,
167{
168 fn from(
169 (inner, state_version): (Vec<(Option<ChildInfo>, StorageCollection)>, StateVersion),
170 ) -> Self {
171 let mut expanded: HashMap<Option<ChildInfo>, BTreeMap<StorageKey, StorageValue>> =
172 HashMap::new();
173 for (child_info, key_values) in inner {
174 let entry = expanded.entry(child_info).or_default();
175 for (key, value) in key_values {
176 if let Some(value) = value {
177 entry.insert(key, value);
178 }
179 }
180 }
181 (expanded, state_version).into()
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::backend::{AsTrieBackend, Backend};
189 use sp_core::storage::StateVersion;
190 use sp_runtime::traits::BlakeTwo256;
191
192 #[test]
194 fn in_memory_with_child_trie_only() {
195 let state_version = StateVersion::default();
196 let storage = new_in_mem::<BlakeTwo256>();
197 let child_info = ChildInfo::new_default(b"1");
198 let child_info = &child_info;
199 let storage = storage.update(
200 vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])],
201 state_version,
202 );
203 let trie_backend = storage.as_trie_backend();
204 assert_eq!(trie_backend.child_storage(child_info, b"2").unwrap(), Some(b"3".to_vec()));
205 let storage_key = child_info.prefixed_storage_key();
206 assert!(trie_backend.storage(storage_key.as_slice()).unwrap().is_some());
207 }
208
209 #[test]
210 fn insert_multiple_times_child_data_works() {
211 let state_version = StateVersion::default();
212 let mut storage = new_in_mem::<BlakeTwo256>();
213 let child_info = ChildInfo::new_default(b"1");
214
215 storage.insert(
216 vec![(Some(child_info.clone()), vec![(b"2".to_vec(), Some(b"3".to_vec()))])],
217 state_version,
218 );
219 storage.insert(
220 vec![(Some(child_info.clone()), vec![(b"1".to_vec(), Some(b"3".to_vec()))])],
221 state_version,
222 );
223
224 assert_eq!(storage.child_storage(&child_info, &b"2"[..]), Ok(Some(b"3".to_vec())));
225 assert_eq!(storage.child_storage(&child_info, &b"1"[..]), Ok(Some(b"3".to_vec())));
226 }
227}