1use tetsy_hash_db::HashDBRef;
18use crate::nibble::NibbleSlice;
19use crate::node::{Node, NodeHandle, decode_hash};
20use crate::node_codec::NodeCodec;
21use crate::rstd::boxed::Box;
22use super::{DBValue, Result, TrieError, Query, TrieLayout, CError, TrieHash};
23
24pub struct Lookup<'a, L: TrieLayout, Q: Query<L::Hash>> {
26 pub db: &'a dyn HashDBRef<L::Hash, DBValue>,
28 pub query: Q,
30 pub hash: TrieHash<L>,
32}
33
34impl<'a, L, Q> Lookup<'a, L, Q>
35where
36 L: TrieLayout,
37 Q: Query<L::Hash>,
38{
39 pub fn look_up(
42 mut self,
43 key: NibbleSlice,
44 ) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>> {
45 let mut partial = key;
46 let mut hash = self.hash;
47 let mut key_nibbles = 0;
48
49 for depth in 0.. {
51 let node_data = match self.db.get(&hash, key.mid(key_nibbles).left()) {
52 Some(value) => value,
53 None => return Err(Box::new(match depth {
54 0 => TrieError::InvalidStateRoot(hash),
55 _ => TrieError::IncompleteDatabase(hash),
56 })),
57 };
58
59 self.query.record(&hash, &node_data, depth);
60
61 let mut node_data = &node_data[..];
64 loop {
65 let decoded = match L::Codec::decode(node_data) {
66 Ok(node) => node,
67 Err(e) => {
68 return Err(Box::new(TrieError::DecoderError(hash, e)))
69 }
70 };
71 let next_node = match decoded {
72 Node::Leaf(slice, value) => {
73 return Ok(match slice == partial {
74 true => Some(self.query.decode(value)),
75 false => None,
76 })
77 }
78 Node::Extension(slice, item) => {
79 if partial.starts_with(&slice) {
80 partial = partial.mid(slice.len());
81 key_nibbles += slice.len();
82 item
83 } else {
84 return Ok(None)
85 }
86 }
87 Node::Branch(children, value) => match partial.is_empty() {
88 true => return Ok(value.map(move |val| self.query.decode(val))),
89 false => match children[partial.at(0) as usize] {
90 Some(x) => {
91 partial = partial.mid(1);
92 key_nibbles += 1;
93 x
94 }
95 None => return Ok(None)
96 }
97 },
98 Node::NibbledBranch(slice, children, value) => {
99 if !partial.starts_with(&slice) {
100 return Ok(None)
101 }
102
103 match partial.len() == slice.len() {
104 true => return Ok(value.map(move |val| self.query.decode(val))),
105 false => match children[partial.at(slice.len()) as usize] {
106 Some(x) => {
107 partial = partial.mid(slice.len() + 1);
108 key_nibbles += slice.len() + 1;
109 x
110 }
111 None => return Ok(None)
112 }
113 }
114 },
115 Node::Empty => return Ok(None),
116 };
117
118 match next_node {
120 NodeHandle::Hash(data) => {
121 hash = decode_hash::<L::Hash>(data)
122 .ok_or_else(|| Box::new(TrieError::InvalidHash(hash, data.to_vec())))?;
123 break;
124 },
125 NodeHandle::Inline(data) => {
126 node_data = data;
127 },
128 }
129 }
130 }
131 Ok(None)
132 }
133}