Skip to main content

trie_db/
triedb.rs

1// Copyright 2017, 2021 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::{
16	iterator::TrieDBRawIterator,
17	lookup::Lookup,
18	nibble::NibbleSlice,
19	node::{decode_hash, NodeHandle, OwnedNode},
20	rstd::boxed::Box,
21	CError, DBValue, Query, Result, Trie, TrieAccess, TrieCache, TrieError, TrieHash, TrieItem,
22	TrieIterator, TrieKeyItem, TrieLayout, TrieRecorder,
23};
24#[cfg(feature = "std")]
25use crate::{
26	nibble::NibbleVec,
27	node::Node,
28	rstd::{fmt, vec::Vec},
29};
30use hash_db::{HashDBRef, Prefix, EMPTY_PREFIX};
31
32/// A builder for creating a [`TrieDB`].
33pub struct TrieDBBuilder<'db, 'cache, L: TrieLayout> {
34	db: &'db dyn HashDBRef<L::Hash, DBValue>,
35	root: &'db TrieHash<L>,
36	cache: Option<&'cache mut dyn TrieCache<L::Codec>>,
37	recorder: Option<&'cache mut dyn TrieRecorder<TrieHash<L>>>,
38}
39
40impl<'db, 'cache, L: TrieLayout> TrieDBBuilder<'db, 'cache, L> {
41	/// Create a new trie-db builder with the backing database `db` and `root`.
42	///
43	/// This doesn't check if `root` exists in the given `db`. If `root` doesn't exist it will fail
44	/// when trying to lookup any key.
45	#[inline]
46	pub fn new(db: &'db dyn HashDBRef<L::Hash, DBValue>, root: &'db TrieHash<L>) -> Self {
47		Self { db, root, cache: None, recorder: None }
48	}
49
50	/// Use the given `cache` for the db.
51	#[inline]
52	pub fn with_cache(mut self, cache: &'cache mut dyn TrieCache<L::Codec>) -> Self {
53		self.cache = Some(cache);
54		self
55	}
56
57	/// Use the given optional `cache` for the db.
58	#[inline]
59	pub fn with_optional_cache<'ocache: 'cache>(
60		mut self,
61		cache: Option<&'ocache mut dyn TrieCache<L::Codec>>,
62	) -> Self {
63		// Make the compiler happy by "converting" the lifetime
64		self.cache = cache.map(|c| c as _);
65		self
66	}
67
68	/// Use the given `recorder` to record trie accesses.
69	#[inline]
70	pub fn with_recorder(mut self, recorder: &'cache mut dyn TrieRecorder<TrieHash<L>>) -> Self {
71		self.recorder = Some(recorder);
72		self
73	}
74
75	/// Use the given optional `recorder` to record trie accesses.
76	#[inline]
77	pub fn with_optional_recorder<'recorder: 'cache>(
78		mut self,
79		recorder: Option<&'recorder mut dyn TrieRecorder<TrieHash<L>>>,
80	) -> Self {
81		// Make the compiler happy by "converting" the lifetime
82		self.recorder = recorder.map(|r| r as _);
83		self
84	}
85
86	/// Build the [`TrieDB`].
87	#[inline]
88	pub fn build(self) -> TrieDB<'db, 'cache, L> {
89		TrieDB {
90			db: self.db,
91			root: self.root,
92			cache: self.cache.map(core::cell::RefCell::new),
93			recorder: self.recorder.map(core::cell::RefCell::new),
94		}
95	}
96}
97
98/// A `Trie` implementation using a generic `HashDB` backing database, a `Hasher`
99/// implementation to generate keys and a `NodeCodec` implementation to encode/decode
100/// the nodes.
101///
102/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object.
103/// Use `get` and `contains` to query values associated with keys in the trie.
104///
105/// # Example
106/// ```ignore
107/// use hash_db::Hasher;
108/// use reference_trie::{RefTrieDBMut, RefTrieDB, Trie, TrieMut};
109/// use trie_db::DBValue;
110/// use keccak_hasher::KeccakHasher;
111/// use memory_db::*;
112///
113/// let mut memdb = MemoryDB::<KeccakHasher, HashKey<_>, _>::default();
114/// let mut root = Default::default();
115/// RefTrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
116/// let t = RefTrieDB::new(&memdb, &root);
117/// assert!(t.contains(b"foo").unwrap());
118/// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar".to_vec());
119/// ```
120pub struct TrieDB<'db, 'cache, L>
121where
122	L: TrieLayout,
123{
124	db: &'db dyn HashDBRef<L::Hash, DBValue>,
125	root: &'db TrieHash<L>,
126	cache: Option<core::cell::RefCell<&'cache mut dyn TrieCache<L::Codec>>>,
127	recorder: Option<core::cell::RefCell<&'cache mut dyn TrieRecorder<TrieHash<L>>>>,
128}
129
130impl<'db, 'cache, L> TrieDB<'db, 'cache, L>
131where
132	L: TrieLayout,
133{
134	/// Get the backing database.
135	pub fn db(&'db self) -> &'db dyn HashDBRef<L::Hash, DBValue> {
136		self.db
137	}
138
139	/// Given some node-describing data `node`, and node key return the actual node RLP.
140	/// This could be a simple identity operation in the case that the node is sufficiently small,
141	/// but may require a database lookup.
142	///
143	/// Return value is the node data and the node hash if the value was looked up in the database
144	/// or None if it was returned raw.
145	///
146	/// `partial_key` is encoded nibble slice that addresses the node.
147	///
148	/// `record_access` should be set to `true` when the access to the trie should be recorded.
149	/// However, this will only be done when there is a recorder set.
150	pub(crate) fn get_raw_or_lookup(
151		&self,
152		parent_hash: TrieHash<L>,
153		node_handle: NodeHandle,
154		partial_key: Prefix,
155		record_access: bool,
156	) -> Result<(OwnedNode<DBValue>, Option<TrieHash<L>>), TrieHash<L>, CError<L>> {
157		let (node_hash, node_data) = match node_handle {
158			NodeHandle::Hash(data) => {
159				let node_hash = decode_hash::<L::Hash>(data)
160					.ok_or_else(|| Box::new(TrieError::InvalidHash(parent_hash, data.to_vec())))?;
161				let node_data = self.db.get(&node_hash, partial_key).ok_or_else(|| {
162					if partial_key == EMPTY_PREFIX {
163						Box::new(TrieError::InvalidStateRoot(node_hash))
164					} else {
165						Box::new(TrieError::IncompleteDatabase(node_hash))
166					}
167				})?;
168
169				(Some(node_hash), node_data)
170			},
171			NodeHandle::Inline(data) => (None, data.to_vec()),
172		};
173		let owned_node = OwnedNode::new::<L::Codec>(node_data)
174			.map_err(|e| Box::new(TrieError::DecoderError(node_hash.unwrap_or(parent_hash), e)))?;
175
176		if record_access {
177			if let Some((hash, recorder)) =
178				node_hash.as_ref().and_then(|h| self.recorder.as_ref().map(|r| (h, r)))
179			{
180				recorder.borrow_mut().record(TrieAccess::EncodedNode {
181					hash: *hash,
182					encoded_node: owned_node.data().into(),
183				});
184			}
185		}
186
187		Ok((owned_node, node_hash))
188	}
189
190	/// Fetch a value under the given `hash`.
191	pub(crate) fn fetch_value(
192		&self,
193		hash: TrieHash<L>,
194		prefix: Prefix,
195	) -> Result<DBValue, TrieHash<L>, CError<L>> {
196		let value = self
197			.db
198			.get(&hash, prefix)
199			.ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?;
200
201		if let Some(recorder) = self.recorder.as_ref() {
202			debug_assert!(prefix.1.is_none(), "A value has never a partial key; qed");
203
204			recorder.borrow_mut().record(TrieAccess::Value {
205				hash,
206				value: value.as_slice().into(),
207				full_key: prefix.0,
208			});
209		}
210
211		Ok(value)
212	}
213}
214
215impl<'db, 'cache, L> Trie<L> for TrieDB<'db, 'cache, L>
216where
217	L: TrieLayout,
218{
219	fn root(&self) -> &TrieHash<L> {
220		self.root
221	}
222
223	fn get_hash(&self, key: &[u8]) -> Result<Option<TrieHash<L>>, TrieHash<L>, CError<L>> {
224		let mut cache = self.cache.as_ref().map(|c| c.borrow_mut());
225		let mut recorder = self.recorder.as_ref().map(|r| r.borrow_mut());
226
227		Lookup::<L, _> {
228			db: self.db,
229			query: |_: &[u8]| (),
230			hash: *self.root,
231			cache: cache.as_mut().map(|c| &mut ***c as &mut dyn TrieCache<L::Codec>),
232			recorder: recorder.as_mut().map(|r| &mut ***r as &mut dyn TrieRecorder<TrieHash<L>>),
233		}
234		.look_up_hash(key, NibbleSlice::new(key))
235	}
236
237	fn get_with<Q: Query<L::Hash>>(
238		&self,
239		key: &[u8],
240		query: Q,
241	) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>> {
242		let mut cache = self.cache.as_ref().map(|c| c.borrow_mut());
243		let mut recorder = self.recorder.as_ref().map(|r| r.borrow_mut());
244
245		Lookup::<L, Q> {
246			db: self.db,
247			query,
248			hash: *self.root,
249			cache: cache.as_mut().map(|c| &mut ***c as &mut dyn TrieCache<L::Codec>),
250			recorder: recorder.as_mut().map(|r| &mut ***r as &mut dyn TrieRecorder<TrieHash<L>>),
251		}
252		.look_up(key, NibbleSlice::new(key))
253	}
254
255	fn iter<'a>(
256		&'a self,
257	) -> Result<
258		Box<dyn TrieIterator<L, Item = TrieItem<TrieHash<L>, CError<L>>> + 'a>,
259		TrieHash<L>,
260		CError<L>,
261	> {
262		TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>)
263	}
264
265	fn key_iter<'a>(
266		&'a self,
267	) -> Result<
268		Box<dyn TrieIterator<L, Item = TrieKeyItem<TrieHash<L>, CError<L>>> + 'a>,
269		TrieHash<L>,
270		CError<L>,
271	> {
272		TrieDBKeyIterator::new(self).map(|iter| Box::new(iter) as Box<_>)
273	}
274}
275
276// This is for pretty debug output only
277#[cfg(feature = "std")]
278struct TrieAwareDebugNode<'db, 'cache, 'a, L>
279where
280	L: TrieLayout,
281{
282	trie: &'db TrieDB<'db, 'cache, L>,
283	node_key: NodeHandle<'a>,
284	partial_key: NibbleVec,
285	index: Option<u8>,
286}
287
288#[cfg(feature = "std")]
289impl<'db, 'cache, 'a, L> fmt::Debug for TrieAwareDebugNode<'db, 'cache, 'a, L>
290where
291	L: TrieLayout,
292{
293	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294		match self.trie.get_raw_or_lookup(
295			<TrieHash<L>>::default(),
296			self.node_key,
297			self.partial_key.as_prefix(),
298			false,
299		) {
300			Ok((owned_node, _node_hash)) => match owned_node.node() {
301				Node::Leaf(slice, value) => {
302					let mut disp = f.debug_struct("Node::Leaf");
303					if let Some(i) = self.index {
304						disp.field("index", &i);
305					}
306					disp.field("slice", &slice).field("value", &value);
307					disp.finish()
308				},
309				Node::Extension(slice, item) => {
310					let mut disp = f.debug_struct("Node::Extension");
311					if let Some(i) = self.index {
312						disp.field("index", &i);
313					}
314					disp.field("slice", &slice).field(
315						"item",
316						&TrieAwareDebugNode {
317							trie: self.trie,
318							node_key: item,
319							partial_key: self
320								.partial_key
321								.clone_append_optional_slice_and_nibble(Some(&slice), None),
322							index: None,
323						},
324					);
325					disp.finish()
326				},
327				Node::Branch(ref nodes, ref value) => {
328					let nodes: Vec<TrieAwareDebugNode<L>> = nodes
329						.into_iter()
330						.enumerate()
331						.filter_map(|(i, n)| n.map(|n| (i, n)))
332						.map(|(i, n)| TrieAwareDebugNode {
333							trie: self.trie,
334							index: Some(i as u8),
335							node_key: n,
336							partial_key: self
337								.partial_key
338								.clone_append_optional_slice_and_nibble(None, Some(i as u8)),
339						})
340						.collect();
341					let mut disp = f.debug_struct("Node::Branch");
342					if let Some(i) = self.index {
343						disp.field("index", &i);
344					}
345					disp.field("nodes", &nodes).field("value", &value);
346					disp.finish()
347				},
348				Node::NibbledBranch(slice, nodes, value) => {
349					let nodes: Vec<TrieAwareDebugNode<L>> = nodes
350						.iter()
351						.enumerate()
352						.filter_map(|(i, n)| n.map(|n| (i, n)))
353						.map(|(i, n)| TrieAwareDebugNode {
354							trie: self.trie,
355							index: Some(i as u8),
356							node_key: n,
357							partial_key: self.partial_key.clone_append_optional_slice_and_nibble(
358								Some(&slice),
359								Some(i as u8),
360							),
361						})
362						.collect();
363					let mut disp = f.debug_struct("Node::NibbledBranch");
364					if let Some(i) = self.index {
365						disp.field("index", &i);
366					}
367					disp.field("slice", &slice).field("nodes", &nodes).field("value", &value);
368					disp.finish()
369				},
370				Node::Empty => {
371					let mut disp = f.debug_struct("Node::Empty");
372					disp.finish()
373				},
374			},
375			Err(e) => f
376				.debug_struct("BROKEN_NODE")
377				.field("index", &self.index)
378				.field("key", &self.node_key)
379				.field("error", &format!("ERROR fetching node: {}", e))
380				.finish(),
381		}
382	}
383}
384
385#[cfg(feature = "std")]
386impl<'db, 'cache, L> fmt::Debug for TrieDB<'db, 'cache, L>
387where
388	L: TrieLayout,
389{
390	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391		f.debug_struct("TrieDB")
392			.field(
393				"root",
394				&TrieAwareDebugNode {
395					trie: self,
396					node_key: NodeHandle::Hash(self.root().as_ref()),
397					partial_key: NibbleVec::new(),
398					index: None,
399				},
400			)
401			.finish()
402	}
403}
404
405/// Iterator for going through all values in the trie in pre-order traversal order.
406pub struct TrieDBIterator<'a, 'cache, L: TrieLayout> {
407	db: &'a TrieDB<'a, 'cache, L>,
408	raw_iter: TrieDBRawIterator<L>,
409}
410
411/// Iterator for going through all of key with values in the trie in pre-order traversal order.
412pub struct TrieDBKeyIterator<'a, 'cache, L: TrieLayout> {
413	db: &'a TrieDB<'a, 'cache, L>,
414	raw_iter: TrieDBRawIterator<L>,
415}
416
417impl<'a, 'cache, L: TrieLayout> TrieDBIterator<'a, 'cache, L> {
418	/// Create a new iterator.
419	pub fn new(db: &'a TrieDB<'a, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
420		Ok(Self { db, raw_iter: TrieDBRawIterator::new(db)? })
421	}
422
423	/// Create a new iterator, but limited to a given prefix.
424	pub fn new_prefixed(
425		db: &'a TrieDB<'a, 'cache, L>,
426		prefix: &[u8],
427	) -> Result<Self, TrieHash<L>, CError<L>> {
428		Ok(Self { db, raw_iter: TrieDBRawIterator::new_prefixed(db, prefix)? })
429	}
430
431	/// Create a new iterator, but limited to a given prefix.
432	/// It then do a seek operation from prefixed context (using `seek` lose
433	/// prefix context by default).
434	pub fn new_prefixed_then_seek(
435		db: &'a TrieDB<'a, 'cache, L>,
436		prefix: &[u8],
437		start_at: &[u8],
438	) -> Result<Self, TrieHash<L>, CError<L>> {
439		Ok(Self { db, raw_iter: TrieDBRawIterator::new_prefixed_then_seek(db, prefix, start_at)? })
440	}
441
442	/// Restore an iterator from a raw iterator.
443	pub fn from_raw(db: &'a TrieDB<'a, 'cache, L>, raw_iter: TrieDBRawIterator<L>) -> Self {
444		Self { db, raw_iter }
445	}
446
447	/// Convert the iterator to a raw iterator.
448	pub fn into_raw(self) -> TrieDBRawIterator<L> {
449		self.raw_iter
450	}
451}
452
453impl<'a, 'cache, L: TrieLayout> TrieIterator<L> for TrieDBIterator<'a, 'cache, L> {
454	/// Position the iterator on the first element with key >= `key`
455	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
456		self.raw_iter.seek(self.db, key).map(|_| ())
457	}
458}
459
460impl<'a, 'cache, L: TrieLayout> TrieDBKeyIterator<'a, 'cache, L> {
461	/// Create a new iterator.
462	pub fn new(db: &'a TrieDB<'a, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
463		Ok(Self { db, raw_iter: TrieDBRawIterator::new(db)? })
464	}
465
466	/// Create a new iterator, but limited to a given prefix.
467	pub fn new_prefixed(
468		db: &'a TrieDB<'a, 'cache, L>,
469		prefix: &[u8],
470	) -> Result<Self, TrieHash<L>, CError<L>> {
471		Ok(Self { db, raw_iter: TrieDBRawIterator::new_prefixed(db, prefix)? })
472	}
473
474	/// Create a new iterator, but limited to a given prefix.
475	/// It then do a seek operation from prefixed context (using `seek` lose
476	/// prefix context by default).
477	pub fn new_prefixed_then_seek(
478		db: &'a TrieDB<'a, 'cache, L>,
479		prefix: &[u8],
480		start_at: &[u8],
481	) -> Result<TrieDBKeyIterator<'a, 'cache, L>, TrieHash<L>, CError<L>> {
482		Ok(Self { db, raw_iter: TrieDBRawIterator::new_prefixed_then_seek(db, prefix, start_at)? })
483	}
484
485	/// Restore an iterator from a raw iterator.
486	pub fn from_raw(db: &'a TrieDB<'a, 'cache, L>, raw_iter: TrieDBRawIterator<L>) -> Self {
487		Self { db, raw_iter }
488	}
489
490	/// Convert the iterator to a raw iterator.
491	pub fn into_raw(self) -> TrieDBRawIterator<L> {
492		self.raw_iter
493	}
494}
495
496impl<'a, 'cache, L: TrieLayout> TrieIterator<L> for TrieDBKeyIterator<'a, 'cache, L> {
497	/// Position the iterator on the first element with key >= `key`
498	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
499		self.raw_iter.seek(self.db, key).map(|_| ())
500	}
501}
502
503impl<'a, 'cache, L: TrieLayout> Iterator for TrieDBIterator<'a, 'cache, L> {
504	type Item = TrieItem<TrieHash<L>, CError<L>>;
505
506	fn next(&mut self) -> Option<Self::Item> {
507		self.raw_iter.next_item(self.db)
508	}
509}
510
511impl<'a, 'cache, L: TrieLayout> Iterator for TrieDBKeyIterator<'a, 'cache, L> {
512	type Item = TrieKeyItem<TrieHash<L>, CError<L>>;
513
514	fn next(&mut self) -> Option<Self::Item> {
515		self.raw_iter.next_key(self.db)
516	}
517}