1use 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
28pub struct TrieDB<'db, L>
51where
52 L: TrieLayout,
53{
54 db: &'db dyn HashDBRef<L::Hash, DBValue>,
55 root: &'db TrieHash<L>,
56 hash_count: usize,
58}
59
60impl<'db, L> TrieDB<'db, L>
61where
62 L: TrieLayout,
63{
64 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 pub fn db(&'db self) -> &'db dyn HashDBRef<L::Hash, DBValue> { self.db }
79
80 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")]
149struct 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
264pub struct TrieDBIterator<'a, L: TrieLayout> {
266 inner: TrieDBNodeIterator<'a, L>,
267}
268
269impl<'a, L: TrieLayout> TrieDBIterator<'a, L> {
270 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 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 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}