tetsy_trie_db/
triedb.rs

1// Copyright 2017, 2020 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 tetsy_hash_db::{HashDBRef, Prefix, EMPTY_PREFIX};
16use crate::nibble::NibbleSlice;
17use crate::iterator::TrieDBNodeIterator;
18use crate::rstd::boxed::Box;
19use super::node::{NodeHandle, Node, OwnedNode, decode_hash};
20use super::lookup::Lookup;
21use super::{Result, DBValue, Trie, TrieItem, TrieError, TrieIterator, Query,
22	TrieLayout, CError, TrieHash};
23use super::nibble::NibbleVec;
24
25#[cfg(feature = "std")]
26use crate::rstd::{fmt, vec::Vec};
27
28/// A `Trie` implementation using a generic `HashDB` backing database, a `Hasher`
29/// implementation to generate keys and a `NodeCodec` implementation to encode/decode
30/// the nodes.
31///
32/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object.
33/// Use `get` and `contains` to query values associated with keys in the trie.
34///
35/// # Example
36/// ```ignore
37/// use tetsy_hash_db::Hasher;
38/// use tetsy_reference_trie::{RefTrieDBMut, RefTrieDB, Trie, TrieMut};
39/// use tetsy_trie_db::DBValue;
40/// use tetsy_keccak_hasher::KeccakHasher;
41/// use tetsy_memory_db::*;
42///
43/// let mut memdb = MemoryDB::<KeccakHasher, HashKey<_>, _>::default();
44/// let mut root = Default::default();
45/// RefTrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
46/// let t = RefTrieDB::new(&memdb, &root).unwrap();
47/// assert!(t.contains(b"foo").unwrap());
48/// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar".to_vec());
49/// ```
50pub struct TrieDB<'db, L>
51where
52	L: TrieLayout,
53{
54	db: &'db dyn HashDBRef<L::Hash, DBValue>,
55	root: &'db TrieHash<L>,
56	/// The number of hashes performed so far in operations on this trie.
57	hash_count: usize,
58}
59
60impl<'db, L> TrieDB<'db, L>
61where
62	L: TrieLayout,
63{
64	/// Create a new trie with the backing database `db` and `root`
65	/// Returns an error if `root` does not exist
66	pub fn new(
67		db: &'db dyn HashDBRef<L::Hash, DBValue>,
68		root: &'db TrieHash<L>
69	) -> Result<Self, TrieHash<L>, CError<L>> {
70		if !db.contains(root, EMPTY_PREFIX) {
71			Err(Box::new(TrieError::InvalidStateRoot(*root)))
72		} else {
73			Ok(TrieDB {db, root, hash_count: 0})
74		}
75	}
76
77	/// Get the backing database.
78	pub fn db(&'db self) -> &'db dyn HashDBRef<L::Hash, DBValue> { self.db }
79
80	/// Given some node-describing data `node`, and node key return the actual node RLP.
81	/// This could be a simple identity operation in the case that the node is sufficiently small,
82	/// but may require a database lookup.
83	///
84	/// Return value is the node data and the node hash if the value was looked up in the database
85	/// or None if it was returned raw.
86	///
87	/// `partial_key` is encoded nibble slice that addresses the node.
88	pub(crate) fn get_raw_or_lookup(
89		&self,
90		parent_hash: TrieHash<L>,
91		node_handle: NodeHandle,
92		partial_key: Prefix,
93	) -> Result<(OwnedNode<DBValue>, Option<TrieHash<L>>), TrieHash<L>, CError<L>> {
94		let (node_hash, node_data) = match node_handle {
95			NodeHandle::Hash(data) => {
96				let node_hash = decode_hash::<L::Hash>(data)
97					.ok_or_else(|| Box::new(TrieError::InvalidHash(parent_hash, data.to_vec())))?;
98				let node_data = self.db
99					.get(&node_hash, partial_key)
100					.ok_or_else(|| {
101						if partial_key == EMPTY_PREFIX {
102							Box::new(TrieError::InvalidStateRoot(node_hash))
103						} else {
104							Box::new(TrieError::IncompleteDatabase(node_hash))
105						}
106					})?;
107
108				(Some(node_hash), node_data)
109			}
110			NodeHandle::Inline(data) => (None, data.to_vec()),
111		};
112		let owned_node = OwnedNode::new::<L::Codec>(node_data)
113			.map_err(|e| Box::new(TrieError::DecoderError(node_hash.unwrap_or(parent_hash), e)))?;
114		Ok((owned_node, node_hash))
115	}
116}
117
118impl<'db, L> Trie<L> for TrieDB<'db, L>
119where
120	L: TrieLayout,
121{
122	fn root(&self) -> &TrieHash<L> { self.root }
123
124	fn get_with<'a, 'key, Q: Query<L::Hash>>(
125		&'a self,
126		key: &'key [u8],
127		query: Q,
128	) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>>
129		where 'a: 'key,
130	{
131		Lookup::<L, Q> {
132			db: self.db,
133			query,
134			hash: *self.root,
135		}.look_up(NibbleSlice::new(key))
136	}
137
138	fn iter<'a>(&'a self)-> Result<
139		Box<dyn TrieIterator<L, Item=TrieItem<TrieHash<L>, CError<L>>> + 'a>,
140		TrieHash<L>,
141		CError<L>,
142	> {
143		TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>)
144	}
145}
146
147
148#[cfg(feature="std")]
149// This is for pretty debug output only
150struct TrieAwareDebugNode<'db, 'a, L>
151where
152	L: TrieLayout,
153{
154	trie: &'db TrieDB<'db, L>,
155	node_key: NodeHandle<'a>,
156	partial_key: NibbleVec,
157	index: Option<u8>,
158}
159
160#[cfg(feature="std")]
161impl<'db, 'a, L> fmt::Debug for TrieAwareDebugNode<'db, 'a, L>
162where
163	L: TrieLayout,
164{
165	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166		match self.trie.get_raw_or_lookup(
167			<TrieHash<L>>::default(),
168			self.node_key,
169			self.partial_key.as_prefix()
170		) {
171			Ok((owned_node, _node_hash)) => match owned_node.node() {
172				Node::Leaf(slice, value) =>
173					match (f.debug_struct("Node::Leaf"), self.index) {
174						(ref mut d, Some(i)) => d.field("index", &i),
175						(ref mut d, _) => d,
176					}
177						.field("slice", &slice)
178						.field("value", &value)
179						.finish(),
180				Node::Extension(slice, item) => {
181					match (f.debug_struct("Node::Extension"), self.index) {
182						(ref mut d, Some(i)) => d.field("index", &i),
183						(ref mut d, _) => d,
184					}
185						.field("slice", &slice)
186						.field("item", &TrieAwareDebugNode {
187							trie: self.trie,
188							node_key: item,
189							partial_key: self.partial_key
190								.clone_append_optional_slice_and_nibble(Some(&slice), None),
191							index: None,
192						})
193						.finish()
194				},
195				Node::Branch(ref nodes, ref value) => {
196					let nodes: Vec<TrieAwareDebugNode<L>> = nodes.into_iter()
197						.enumerate()
198						.filter_map(|(i, n)| n.map(|n| (i, n)))
199						.map(|(i, n)| TrieAwareDebugNode {
200							trie: self.trie,
201							index: Some(i as u8),
202							node_key: n,
203							partial_key: self.partial_key
204								.clone_append_optional_slice_and_nibble(None, Some(i as u8)),
205						})
206						.collect();
207					match (f.debug_struct("Node::Branch"), self.index) {
208						(ref mut d, Some(ref i)) => d.field("index", i),
209						(ref mut d, _) => d,
210					}
211						.field("nodes", &nodes)
212						.field("value", &value)
213						.finish()
214				},
215				Node::NibbledBranch(slice, nodes, value) => {
216					let nodes: Vec<TrieAwareDebugNode<L>> = nodes.iter()
217						.enumerate()
218						.filter_map(|(i, n)| n.map(|n| (i, n)))
219						.map(|(i, n)| TrieAwareDebugNode {
220							trie: self.trie,
221							index: Some(i as u8),
222							node_key: n,
223							partial_key: self.partial_key
224								.clone_append_optional_slice_and_nibble(Some(&slice), Some(i as u8)),
225						}).collect();
226					match (f.debug_struct("Node::NibbledBranch"), self.index) {
227						(ref mut d, Some(ref i)) => d.field("index", i),
228						(ref mut d, _) => d,
229					}
230						.field("slice", &slice)
231						.field("nodes", &nodes)
232						.field("value", &value)
233						.finish()
234				},
235				Node::Empty => f.debug_struct("Node::Empty").finish(),
236			},
237			Err(e) => f.debug_struct("BROKEN_NODE")
238				.field("index", &self.index)
239				.field("key", &self.node_key)
240				.field("error", &format!("ERROR fetching node: {}", e))
241				.finish(),
242		}
243	}
244}
245
246#[cfg(feature="std")]
247impl<'db, L> fmt::Debug for TrieDB<'db, L>
248where
249	L: TrieLayout,
250{
251	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252		f.debug_struct("TrieDB")
253			.field("hash_count", &self.hash_count)
254			.field("root", &TrieAwareDebugNode {
255				trie: self,
256				node_key: NodeHandle::Hash(self.root().as_ref()),
257				partial_key: NibbleVec::new(),
258				index: None,
259			})
260			.finish()
261	}
262}
263
264/// Iterator for going through all values in the trie in pre-order traversal order.
265pub struct TrieDBIterator<'a, L: TrieLayout> {
266	inner: TrieDBNodeIterator<'a, L>,
267}
268
269impl<'a, L: TrieLayout> TrieDBIterator<'a, L> {
270	/// Create a new iterator.
271	pub fn new(db: &'a TrieDB<L>) -> Result<TrieDBIterator<'a, L>, TrieHash<L>, CError<L>> {
272		let inner = TrieDBNodeIterator::new(db)?;
273		Ok(TrieDBIterator { inner })
274	}
275
276	/// Create a new iterator, but limited to a given prefix.
277	pub fn new_prefixed(db: &'a TrieDB<L>, prefix: &[u8]) -> Result<TrieDBIterator<'a, L>, TrieHash<L>, CError<L>> {
278		let mut inner = TrieDBNodeIterator::new(db)?;
279		inner.prefix(prefix)?;
280
281		Ok(TrieDBIterator {
282			inner,
283		})
284	}
285
286}
287
288impl<'a, L: TrieLayout> TrieIterator<L> for TrieDBIterator<'a, L> {
289	/// Position the iterator on the first element with key >= `key`
290	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
291		TrieIterator::seek(&mut self.inner, key)
292	}
293}
294
295impl<'a, L: TrieLayout> Iterator for TrieDBIterator<'a, L> {
296	type Item = TrieItem<'a, TrieHash<L>, CError<L>>;
297
298	fn next(&mut self) -> Option<Self::Item> {
299		while let Some(item) = self.inner.next() {
300			match item {
301				Ok((mut prefix, _, node)) => {
302					let maybe_value = match node.node() {
303						Node::Leaf(partial, value) => {
304							prefix.append_partial(partial.right());
305							Some(value)
306						}
307						Node::Branch(_, value) => value,
308						Node::NibbledBranch(partial, _, value) => {
309							prefix.append_partial(partial.right());
310							value
311						}
312						_ => None,
313					};
314					if let Some(value) = maybe_value {
315						let (key_slice, maybe_extra_nibble) = prefix.as_prefix();
316						let key = key_slice.to_vec();
317						if let Some(extra_nibble) = maybe_extra_nibble {
318							return Some(Err(Box::new(
319								TrieError::ValueAtIncompleteKey(key, extra_nibble)
320							)));
321						}
322						return Some(Ok((key, value.to_vec())));
323					}
324				},
325				Err(err) => return Some(Err(err)),
326			}
327		}
328		None
329	}
330}