tp_state_machine/
trie_backend_essence.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Trie-based state machine backend essence used to read values
19//! from storage.
20
21#[cfg(feature = "std")]
22use std::sync::Arc;
23use tetcore_std::{ops::Deref, boxed::Box, vec::Vec};
24use crate::{warn, debug};
25use tetsy_hash_db::{self, Hasher, Prefix};
26use tp_trie::{Trie, MemoryDB, PrefixedMemoryDB, DBValue,
27	empty_child_trie_root, read_trie_value, read_child_trie_value,
28	for_keys_in_child_trie, KeySpacedDB, TrieDBIterator};
29use tp_trie::trie_types::{TrieDB, TrieError, Layout};
30use crate::{backend::Consolidate, StorageKey, StorageValue};
31use tet_core::storage::ChildInfo;
32use codec::Encode;
33
34#[cfg(not(feature = "std"))]
35macro_rules! format {
36	($($arg:tt)+) => (
37		crate::DefaultError
38	);
39}
40
41type Result<V> = tetcore_std::result::Result<V, crate::DefaultError>;
42
43/// Patricia trie-based storage trait.
44pub trait Storage<H: Hasher>: Send + Sync {
45	/// Get a trie node.
46	fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>>;
47}
48
49/// Patricia trie-based pairs storage essence.
50pub struct TrieBackendEssence<S: TrieBackendStorage<H>, H: Hasher> {
51	storage: S,
52	root: H::Out,
53	empty: H::Out,
54}
55
56impl<S: TrieBackendStorage<H>, H: Hasher> TrieBackendEssence<S, H> where H::Out: Encode {
57	/// Create new trie-based backend.
58	pub fn new(storage: S, root: H::Out) -> Self {
59		TrieBackendEssence {
60			storage,
61			root,
62			empty: H::hash(&[0u8]),
63		}
64	}
65
66	/// Get backend storage reference.
67	pub fn backend_storage(&self) -> &S {
68		&self.storage
69	}
70
71	/// Get backend storage reference.
72	pub fn backend_storage_mut(&mut self) -> &mut S {
73		&mut self.storage
74	}
75
76	/// Get trie root.
77	pub fn root(&self) -> &H::Out {
78		&self.root
79	}
80
81	/// Set trie root. This is useful for testing.
82	pub fn set_root(&mut self, root: H::Out) {
83		self.root = root;
84	}
85
86	/// Consumes self and returns underlying storage.
87	pub fn into_storage(self) -> S {
88		self.storage
89	}
90
91	/// Return the next key in the trie i.e. the minimum key that is strictly superior to `key` in
92	/// lexicographic order.
93	pub fn next_storage_key(&self, key: &[u8]) -> Result<Option<StorageKey>> {
94		self.next_storage_key_from_root(&self.root, None, key)
95	}
96
97	/// Access the root of the child storage in its parent trie
98	fn child_root(&self, child_info: &ChildInfo) -> Result<Option<StorageValue>> {
99		self.storage(child_info.prefixed_storage_key().as_slice())
100	}
101
102	/// Return the next key in the child trie i.e. the minimum key that is strictly superior to
103	/// `key` in lexicographic order.
104	pub fn next_child_storage_key(
105		&self,
106		child_info: &ChildInfo,
107		key: &[u8],
108	) -> Result<Option<StorageKey>> {
109		let child_root = match self.child_root(child_info)? {
110			Some(child_root) => child_root,
111			None => return Ok(None),
112		};
113
114		let mut hash = H::Out::default();
115
116		if child_root.len() != hash.as_ref().len() {
117			return Err(format!("Invalid child storage hash at {:?}", child_info.storage_key()));
118		}
119		// note: child_root and hash must be same size, panics otherwise.
120		hash.as_mut().copy_from_slice(&child_root[..]);
121
122		self.next_storage_key_from_root(&hash, Some(child_info), key)
123	}
124
125	/// Return next key from main trie or child trie by providing corresponding root.
126	fn next_storage_key_from_root(
127		&self,
128		root: &H::Out,
129		child_info: Option<&ChildInfo>,
130		key: &[u8],
131	) -> Result<Option<StorageKey>> {
132		let dyn_eph: &dyn tetsy_hash_db::HashDBRef<_, _>;
133		let keyspace_eph;
134		if let Some(child_info) = child_info.as_ref() {
135			keyspace_eph = KeySpacedDB::new(self, child_info.keyspace());
136			dyn_eph = &keyspace_eph;
137		} else {
138			dyn_eph = self;
139		}
140
141		let trie = TrieDB::<H>::new(dyn_eph, root)
142			.map_err(|e| format!("TrieDB creation error: {}", e))?;
143		let mut iter = trie.iter()
144			.map_err(|e| format!("TrieDB iteration error: {}", e))?;
145
146		// The key just after the one given in input, basically `key++0`.
147		// Note: We are sure this is the next key if:
148		// * size of key has no limit (i.e. we can always add 0 to the path),
149		// * and no keys can be inserted between `key` and `key++0` (this is ensured by tet-io).
150		let mut potential_next_key = Vec::with_capacity(key.len() + 1);
151		potential_next_key.extend_from_slice(key);
152		potential_next_key.push(0);
153
154		iter.seek(&potential_next_key)
155			.map_err(|e| format!("TrieDB iterator seek error: {}", e))?;
156
157		let next_element = iter.next();
158
159		let next_key = if let Some(next_element) = next_element {
160			let (next_key, _) = next_element
161				.map_err(|e| format!("TrieDB iterator next error: {}", e))?;
162			Some(next_key)
163		} else {
164			None
165		};
166
167		Ok(next_key)
168	}
169
170	/// Get the value of storage at given key.
171	pub fn storage(&self, key: &[u8]) -> Result<Option<StorageValue>> {
172		let map_e = |e| format!("Trie lookup error: {}", e);
173
174		read_trie_value::<Layout<H>, _>(self, &self.root, key).map_err(map_e)
175	}
176
177	/// Get the value of child storage at given key.
178	pub fn child_storage(
179		&self,
180		child_info: &ChildInfo,
181		key: &[u8],
182	) -> Result<Option<StorageValue>> {
183		let root = self.child_root(child_info)?
184			.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode());
185
186		let map_e = |e| format!("Trie lookup error: {}", e);
187
188		read_child_trie_value::<Layout<H>, _>(child_info.keyspace(), self, &root, key)
189			.map_err(map_e)
190	}
191
192	/// Retrieve all entries keys of child storage and call `f` for each of those keys.
193	/// Aborts as soon as `f` returns false.
194	pub fn apply_to_child_keys_while<F: FnMut(&[u8]) -> bool>(
195		&self,
196		child_info: &ChildInfo,
197		f: F,
198	) {
199		let root = match self.child_root(child_info) {
200			Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode()),
201			Err(e) => {
202				debug!(target: "trie", "Error while iterating child storage: {}", e);
203				return;
204			}
205		};
206
207		if let Err(e) = for_keys_in_child_trie::<Layout<H>, _, _>(
208			child_info.keyspace(),
209			self,
210			&root,
211			f,
212		) {
213			debug!(target: "trie", "Error while iterating child storage: {}", e);
214		}
215	}
216
217	/// Execute given closure for all keys starting with prefix.
218	pub fn for_child_keys_with_prefix<F: FnMut(&[u8])>(
219		&self,
220		child_info: &ChildInfo,
221		prefix: &[u8],
222		mut f: F,
223	) {
224		let root_vec = match self.child_root(child_info) {
225			Ok(v) => v.unwrap_or_else(|| empty_child_trie_root::<Layout<H>>().encode()),
226			Err(e) => {
227				debug!(target: "trie", "Error while iterating child storage: {}", e);
228				return;
229			}
230		};
231		let mut root = H::Out::default();
232		root.as_mut().copy_from_slice(&root_vec);
233		self.keys_values_with_prefix_inner(&root, prefix, |k, _v| f(k), Some(child_info))
234	}
235
236	/// Execute given closure for all keys starting with prefix.
237	pub fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], mut f: F) {
238		self.keys_values_with_prefix_inner(&self.root, prefix, |k, _v| f(k), None)
239	}
240
241	fn keys_values_with_prefix_inner<F: FnMut(&[u8], &[u8])>(
242		&self,
243		root: &H::Out,
244		prefix: &[u8],
245		mut f: F,
246		child_info: Option<&ChildInfo>,
247	) {
248		let mut iter = move |db| -> tetcore_std::result::Result<(), Box<TrieError<H::Out>>> {
249			let trie = TrieDB::<H>::new(db, root)?;
250
251			for x in TrieDBIterator::new_prefixed(&trie, prefix)? {
252				let (key, value) = x?;
253
254				debug_assert!(key.starts_with(prefix));
255
256				f(&key, &value);
257			}
258
259			Ok(())
260		};
261
262		let result = if let Some(child_info) = child_info {
263			let db = KeySpacedDB::new(self, child_info.keyspace());
264			iter(&db)
265		} else {
266			iter(self)
267		};
268		if let Err(e) = result {
269			debug!(target: "trie", "Error while iterating by prefix: {}", e);
270		}
271	}
272
273	/// Execute given closure for all key and values starting with prefix.
274	pub fn for_key_values_with_prefix<F: FnMut(&[u8], &[u8])>(&self, prefix: &[u8], f: F) {
275		self.keys_values_with_prefix_inner(&self.root, prefix, f, None)
276	}
277}
278
279pub(crate) struct Ephemeral<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> {
280	storage: &'a S,
281	overlay: &'a mut S::Overlay,
282}
283
284impl<'a, S: 'a + TrieBackendStorage<H>, H: 'a + Hasher> tetsy_hash_db::AsHashDB<H, DBValue>
285	for Ephemeral<'a, S, H>
286{
287	fn as_hash_db<'b>(&'b self) -> &'b (dyn tetsy_hash_db::HashDB<H, DBValue> + 'b) { self }
288	fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn tetsy_hash_db::HashDB<H, DBValue> + 'b) { self }
289}
290
291impl<'a, S: TrieBackendStorage<H>, H: Hasher> Ephemeral<'a, S, H> {
292	pub fn new(storage: &'a S, overlay: &'a mut S::Overlay) -> Self {
293		Ephemeral {
294			storage,
295			overlay,
296		}
297	}
298}
299
300impl<'a, S: 'a + TrieBackendStorage<H>, H: Hasher> tetsy_hash_db::HashDB<H, DBValue>
301	for Ephemeral<'a, S, H>
302{
303	fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
304		if let Some(val) = tetsy_hash_db::HashDB::get(self.overlay, key, prefix) {
305			Some(val)
306		} else {
307			match self.storage.get(&key, prefix) {
308				Ok(x) => x,
309				Err(e) => {
310					warn!(target: "trie", "Failed to read from DB: {}", e);
311					None
312				},
313			}
314		}
315	}
316
317	fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
318		tetsy_hash_db::HashDB::get(self, key, prefix).is_some()
319	}
320
321	fn insert(&mut self, prefix: Prefix, value: &[u8]) -> H::Out {
322		tetsy_hash_db::HashDB::insert(self.overlay, prefix, value)
323	}
324
325	fn emplace(&mut self, key: H::Out, prefix: Prefix, value: DBValue) {
326		tetsy_hash_db::HashDB::emplace(self.overlay, key, prefix, value)
327	}
328
329	fn remove(&mut self, key: &H::Out, prefix: Prefix) {
330		tetsy_hash_db::HashDB::remove(self.overlay, key, prefix)
331	}
332}
333
334impl<'a, S: 'a + TrieBackendStorage<H>, H: Hasher> tetsy_hash_db::HashDBRef<H, DBValue>
335	for Ephemeral<'a, S, H>
336{
337	fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
338		tetsy_hash_db::HashDB::get(self, key, prefix)
339	}
340
341	fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
342		tetsy_hash_db::HashDB::contains(self, key, prefix)
343	}
344}
345
346/// Key-value pairs storage that is used by trie backend essence.
347pub trait TrieBackendStorage<H: Hasher>: Send + Sync {
348	/// Type of in-memory overlay.
349	type Overlay: tetsy_hash_db::HashDB<H, DBValue> + Default + Consolidate;
350	/// Get the value stored at key.
351	fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>>;
352}
353
354// This implementation is used by normal storage trie clients.
355#[cfg(feature = "std")]
356impl<H: Hasher> TrieBackendStorage<H> for Arc<dyn Storage<H>> {
357	type Overlay = PrefixedMemoryDB<H>;
358
359	fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>> {
360		Storage::<H>::get(self.deref(), key, prefix)
361	}
362}
363
364// This implementation is used by test storage trie clients.
365impl<H: Hasher> TrieBackendStorage<H> for PrefixedMemoryDB<H> {
366	type Overlay = PrefixedMemoryDB<H>;
367
368	fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>> {
369		Ok(tetsy_hash_db::HashDB::get(self, key, prefix))
370	}
371}
372
373impl<H: Hasher> TrieBackendStorage<H> for MemoryDB<H> {
374	type Overlay = MemoryDB<H>;
375
376	fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>> {
377		Ok(tetsy_hash_db::HashDB::get(self, key, prefix))
378	}
379}
380
381impl<S: TrieBackendStorage<H>, H: Hasher> tetsy_hash_db::AsHashDB<H, DBValue>
382	for TrieBackendEssence<S, H>
383{
384	fn as_hash_db<'b>(&'b self) -> &'b (dyn tetsy_hash_db::HashDB<H, DBValue> + 'b) { self }
385	fn as_hash_db_mut<'b>(&'b mut self) -> &'b mut (dyn tetsy_hash_db::HashDB<H, DBValue> + 'b) { self }
386}
387
388impl<S: TrieBackendStorage<H>, H: Hasher> tetsy_hash_db::HashDB<H, DBValue>
389	for TrieBackendEssence<S, H>
390{
391	fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
392		if *key == self.empty {
393			return Some([0u8].to_vec())
394		}
395		match self.storage.get(&key, prefix) {
396			Ok(x) => x,
397			Err(e) => {
398				warn!(target: "trie", "Failed to read from DB: {}", e);
399				None
400			},
401		}
402	}
403
404	fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
405		tetsy_hash_db::HashDB::get(self, key, prefix).is_some()
406	}
407
408	fn insert(&mut self, _prefix: Prefix, _value: &[u8]) -> H::Out {
409		unimplemented!();
410	}
411
412	fn emplace(&mut self, _key: H::Out, _prefix: Prefix, _value: DBValue) {
413		unimplemented!();
414	}
415
416	fn remove(&mut self, _key: &H::Out, _prefix: Prefix) {
417		unimplemented!();
418	}
419}
420
421impl<S: TrieBackendStorage<H>, H: Hasher> tetsy_hash_db::HashDBRef<H, DBValue>
422	for TrieBackendEssence<S, H>
423{
424	fn get(&self, key: &H::Out, prefix: Prefix) -> Option<DBValue> {
425		tetsy_hash_db::HashDB::get(self, key, prefix)
426	}
427
428	fn contains(&self, key: &H::Out, prefix: Prefix) -> bool {
429		tetsy_hash_db::HashDB::contains(self, key, prefix)
430	}
431}
432
433
434#[cfg(test)]
435mod test {
436	use tet_core::{Blake2Hasher, H256};
437	use tp_trie::{TrieMut, PrefixedMemoryDB, trie_types::TrieDBMut, KeySpacedDBMut};
438	use super::*;
439
440	#[test]
441	fn next_storage_key_and_next_child_storage_key_work() {
442		let child_info = ChildInfo::new_default(b"MyChild");
443		let child_info = &child_info;
444		// Contains values
445		let mut root_1 = H256::default();
446		// Contains child trie
447		let mut root_2 = H256::default();
448
449		let mut mdb = PrefixedMemoryDB::<Blake2Hasher>::default();
450		{
451			let mut trie = TrieDBMut::new(&mut mdb, &mut root_1);
452			trie.insert(b"3", &[1]).expect("insert failed");
453			trie.insert(b"4", &[1]).expect("insert failed");
454			trie.insert(b"6", &[1]).expect("insert failed");
455		}
456		{
457			let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace());
458			// reuse of root_1 implicitly assert child trie root is same
459			// as top trie (contents must remain the same).
460			let mut trie = TrieDBMut::new(&mut mdb, &mut root_1);
461			trie.insert(b"3", &[1]).expect("insert failed");
462			trie.insert(b"4", &[1]).expect("insert failed");
463			trie.insert(b"6", &[1]).expect("insert failed");
464		}
465		{
466			let mut trie = TrieDBMut::new(&mut mdb, &mut root_2);
467			trie.insert(child_info.prefixed_storage_key().as_slice(), root_1.as_ref())
468				.expect("insert failed");
469		};
470
471		let essence_1 = TrieBackendEssence::new(mdb, root_1);
472
473		assert_eq!(essence_1.next_storage_key(b"2"), Ok(Some(b"3".to_vec())));
474		assert_eq!(essence_1.next_storage_key(b"3"), Ok(Some(b"4".to_vec())));
475		assert_eq!(essence_1.next_storage_key(b"4"), Ok(Some(b"6".to_vec())));
476		assert_eq!(essence_1.next_storage_key(b"5"), Ok(Some(b"6".to_vec())));
477		assert_eq!(essence_1.next_storage_key(b"6"), Ok(None));
478
479		let mdb = essence_1.into_storage();
480		let essence_2 = TrieBackendEssence::new(mdb, root_2);
481
482		assert_eq!(
483			essence_2.next_child_storage_key(child_info, b"2"), Ok(Some(b"3".to_vec()))
484		);
485		assert_eq!(
486			essence_2.next_child_storage_key(child_info, b"3"), Ok(Some(b"4".to_vec()))
487		);
488		assert_eq!(
489			essence_2.next_child_storage_key(child_info, b"4"), Ok(Some(b"6".to_vec()))
490		);
491		assert_eq!(
492			essence_2.next_child_storage_key(child_info, b"5"), Ok(Some(b"6".to_vec()))
493		);
494		assert_eq!(
495			essence_2.next_child_storage_key(child_info, b"6"), Ok(None)
496		);
497	}
498}