1use crate::{
18 nibble::NibbleSlice,
19 node::{decode_hash, Node, NodeHandle, NodeHandleOwned, NodeOwned, Value, ValueOwned},
20 node_codec::NodeCodec,
21 rstd::boxed::Box,
22 Bytes, CError, CachedValue, DBValue, Query, RecordedForKey, Result, TrieAccess, TrieCache,
23 TrieError, TrieHash, TrieLayout, TrieRecorder,
24};
25use hash_db::{HashDBRef, Hasher, Prefix};
26
27pub struct Lookup<'a, 'cache, L: TrieLayout, Q: Query<L::Hash>> {
29 pub db: &'a dyn HashDBRef<L::Hash, DBValue>,
31 pub query: Q,
33 pub hash: TrieHash<L>,
35 pub cache: Option<&'cache mut dyn TrieCache<L::Codec>>,
37 pub recorder: Option<&'cache mut dyn TrieRecorder<TrieHash<L>>>,
39}
40
41impl<'a, 'cache, L, Q> Lookup<'a, 'cache, L, Q>
42where
43 L: TrieLayout,
44 Q: Query<L::Hash>,
45{
46 fn load_value(
53 v: Value,
54 prefix: Prefix,
55 full_key: &[u8],
56 db: &dyn HashDBRef<L::Hash, DBValue>,
57 recorder: &mut Option<&mut dyn TrieRecorder<TrieHash<L>>>,
58 query: Q,
59 ) -> Result<Q::Item, TrieHash<L>, CError<L>> {
60 match v {
61 Value::Inline(value) => Ok(query.decode(&value)),
62 Value::Node(hash) => {
63 let mut res = TrieHash::<L>::default();
64 res.as_mut().copy_from_slice(hash);
65 if let Some(value) = db.get(&res, prefix) {
66 if let Some(recorder) = recorder {
67 recorder.record(TrieAccess::Value {
68 hash: res,
69 value: value.as_slice().into(),
70 full_key,
71 });
72 }
73
74 Ok(query.decode(&value))
75 } else {
76 Err(Box::new(TrieError::IncompleteDatabase(res)))
77 }
78 },
79 }
80 }
81
82 fn load_owned_value(
89 v: ValueOwned<TrieHash<L>>,
90 prefix: Prefix,
91 full_key: &[u8],
92 cache: &mut dyn crate::TrieCache<L::Codec>,
93 db: &dyn HashDBRef<L::Hash, DBValue>,
94 recorder: &mut Option<&mut dyn TrieRecorder<TrieHash<L>>>,
95 ) -> Result<(Bytes, TrieHash<L>), TrieHash<L>, CError<L>> {
96 match v {
97 ValueOwned::Inline(value, hash) => Ok((value.clone(), hash)),
98 ValueOwned::Node(hash) => {
99 let node = cache.get_or_insert_node(hash, &mut || {
100 let value = db
101 .get(&hash, prefix)
102 .ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?;
103
104 Ok(NodeOwned::Value(value.into(), hash))
105 })?;
106
107 let value = node
108 .data()
109 .expect(
110 "We are caching a `NodeOwned::Value` for a value node \
111 hash and this cached node has always data attached; qed",
112 )
113 .clone();
114
115 if let Some(recorder) = recorder {
116 recorder.record(TrieAccess::Value {
117 hash,
118 value: value.as_ref().into(),
119 full_key,
120 });
121 }
122
123 Ok((value, hash))
124 },
125 }
126 }
127
128 fn record<'b>(&mut self, get_access: impl FnOnce() -> TrieAccess<'b, TrieHash<L>>)
129 where
130 TrieHash<L>: 'b,
131 {
132 if let Some(recorder) = self.recorder.as_mut() {
133 recorder.record(get_access());
134 }
135 }
136
137 pub fn look_up(
144 mut self,
145 full_key: &[u8],
146 nibble_key: NibbleSlice,
147 ) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>> {
148 match self.cache.take() {
149 Some(cache) => self.look_up_with_cache(full_key, nibble_key, cache),
150 None => self.look_up_without_cache(nibble_key, full_key, Self::load_value),
151 }
152 }
153
154 pub fn look_up_hash(
159 mut self,
160 full_key: &[u8],
161 nibble_key: NibbleSlice,
162 ) -> Result<Option<TrieHash<L>>, TrieHash<L>, CError<L>> {
163 match self.cache.take() {
164 Some(cache) => self.look_up_hash_with_cache(full_key, nibble_key, cache),
165 None => self.look_up_without_cache(
166 nibble_key,
167 full_key,
168 |v, _, full_key, _, recorder, _| {
169 Ok(match v {
170 Value::Inline(v) => L::Hash::hash(&v),
171 Value::Node(hash_bytes) => {
172 if let Some(recoder) = recorder.as_mut() {
173 recoder.record(TrieAccess::Hash { full_key });
174 }
175
176 let mut hash = TrieHash::<L>::default();
177 hash.as_mut().copy_from_slice(hash_bytes);
178 hash
179 },
180 })
181 },
182 ),
183 }
184 }
185
186 fn look_up_hash_with_cache(
190 mut self,
191 full_key: &[u8],
192 nibble_key: NibbleSlice,
193 cache: &mut dyn crate::TrieCache<L::Codec>,
194 ) -> Result<Option<TrieHash<L>>, TrieHash<L>, CError<L>> {
195 let value_cache_allowed = self
196 .recorder
197 .as_ref()
198 .map(|r| !r.trie_nodes_recorded_for_key(full_key).is_none())
200 .unwrap_or(true);
202
203 let res = if let Some(hash) = value_cache_allowed
204 .then(|| cache.lookup_value_for_key(full_key).map(|v| v.hash()))
205 .flatten()
206 {
207 hash
208 } else {
209 let hash_and_value = self.look_up_with_cache_internal(
210 nibble_key,
211 full_key,
212 cache,
213 |value, _, full_key, _, _, recorder| match value {
214 ValueOwned::Inline(value, hash) => Ok((hash, Some(value.clone()))),
215 ValueOwned::Node(hash) => {
216 if let Some(recoder) = recorder.as_mut() {
217 recoder.record(TrieAccess::Hash { full_key });
218 }
219
220 Ok((hash, None))
221 },
222 },
223 )?;
224
225 match &hash_and_value {
226 Some((hash, Some(value))) =>
227 cache.cache_value_for_key(full_key, (value.clone(), *hash).into()),
228 Some((hash, None)) => cache.cache_value_for_key(full_key, (*hash).into()),
229 None => cache.cache_value_for_key(full_key, CachedValue::NonExisting),
230 }
231
232 hash_and_value.map(|v| v.0)
233 };
234
235 Ok(res)
236 }
237
238 fn look_up_with_cache(
243 mut self,
244 full_key: &[u8],
245 nibble_key: NibbleSlice,
246 cache: &mut dyn crate::TrieCache<L::Codec>,
247 ) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>> {
248 let trie_nodes_recorded =
249 self.recorder.as_ref().map(|r| r.trie_nodes_recorded_for_key(full_key));
250
251 let (value_cache_allowed, value_recording_required) = match trie_nodes_recorded {
252 Some(RecordedForKey::Value) | None => (true, false),
255 Some(RecordedForKey::Hash) => (true, true),
258 Some(RecordedForKey::None) => (false, true),
260 };
261
262 let lookup_data = |lookup: &mut Self,
263 cache: &mut dyn crate::TrieCache<L::Codec>|
264 -> Result<Option<Bytes>, TrieHash<L>, CError<L>> {
265 let data = lookup.look_up_with_cache_internal(
266 nibble_key,
267 full_key,
268 cache,
269 Self::load_owned_value,
270 )?;
271
272 cache.cache_value_for_key(full_key, data.clone().into());
273
274 Ok(data.map(|d| d.0))
275 };
276
277 let res = match value_cache_allowed.then(|| cache.lookup_value_for_key(full_key)).flatten()
278 {
279 Some(CachedValue::NonExisting) => None,
280 Some(CachedValue::ExistingHash(hash)) => {
281 let data = Self::load_owned_value(
282 ValueOwned::Node(*hash),
285 nibble_key.original_data_as_prefix(),
286 full_key,
287 cache,
288 self.db,
289 &mut self.recorder,
290 )?;
291
292 cache.cache_value_for_key(full_key, data.clone().into());
293
294 Some(data.0)
295 },
296 Some(CachedValue::Existing { data, hash, .. }) =>
297 if let Some(data) = data.upgrade() {
298 let is_inline =
301 L::MAX_INLINE_VALUE.map_or(true, |max| max as usize > data.as_ref().len());
302 if value_recording_required && !is_inline {
303 self.record(|| TrieAccess::Value {
305 hash: *hash,
306 value: data.as_ref().into(),
307 full_key,
308 });
309 }
310
311 Some(data)
312 } else {
313 lookup_data(&mut self, cache)?
314 },
315 None => lookup_data(&mut self, cache)?,
316 };
317
318 Ok(res.map(|v| self.query.decode(&v)))
319 }
320
321 fn look_up_with_cache_internal<R>(
324 &mut self,
325 nibble_key: NibbleSlice,
326 full_key: &[u8],
327 cache: &mut dyn crate::TrieCache<L::Codec>,
328 load_value_owned: impl Fn(
329 ValueOwned<TrieHash<L>>,
330 Prefix,
331 &[u8],
332 &mut dyn crate::TrieCache<L::Codec>,
333 &dyn HashDBRef<L::Hash, DBValue>,
334 &mut Option<&mut dyn TrieRecorder<TrieHash<L>>>,
335 ) -> Result<R, TrieHash<L>, CError<L>>,
336 ) -> Result<Option<R>, TrieHash<L>, CError<L>> {
337 let mut partial = nibble_key;
338 let mut hash = self.hash;
339 let mut key_nibbles = 0;
340
341 for depth in 0.. {
343 let mut node = cache.get_or_insert_node(hash, &mut || {
344 let node_data = match self.db.get(&hash, nibble_key.mid(key_nibbles).left()) {
345 Some(value) => value,
346 None =>
347 return Err(Box::new(match depth {
348 0 => TrieError::InvalidStateRoot(hash),
349 _ => TrieError::IncompleteDatabase(hash),
350 })),
351 };
352
353 let decoded = match L::Codec::decode(&node_data[..]) {
354 Ok(node) => node,
355 Err(e) => return Err(Box::new(TrieError::DecoderError(hash, e))),
356 };
357
358 decoded.to_owned_node::<L>()
359 })?;
360
361 self.record(|| TrieAccess::NodeOwned { hash, node_owned: node });
362
363 loop {
366 let next_node = match node {
367 NodeOwned::Leaf(slice, value) =>
368 return if partial == *slice {
369 let value = (*value).clone();
370 drop(node);
371 load_value_owned(
372 value,
373 nibble_key.original_data_as_prefix(),
374 full_key,
375 cache,
376 self.db,
377 &mut self.recorder,
378 )
379 .map(Some)
380 } else {
381 self.record(|| TrieAccess::NonExisting { full_key });
382
383 Ok(None)
384 },
385 NodeOwned::Extension(slice, item) =>
386 if partial.starts_with_vec(&slice) {
387 partial = partial.mid(slice.len());
388 key_nibbles += slice.len();
389 item
390 } else {
391 self.record(|| TrieAccess::NonExisting { full_key });
392
393 return Ok(None)
394 },
395 NodeOwned::Branch(children, value) =>
396 if partial.is_empty() {
397 return if let Some(value) = value.clone() {
398 drop(node);
399 load_value_owned(
400 value,
401 nibble_key.original_data_as_prefix(),
402 full_key,
403 cache,
404 self.db,
405 &mut self.recorder,
406 )
407 .map(Some)
408 } else {
409 self.record(|| TrieAccess::NonExisting { full_key });
410
411 Ok(None)
412 }
413 } else {
414 match &children[partial.at(0) as usize] {
415 Some(x) => {
416 partial = partial.mid(1);
417 key_nibbles += 1;
418 x
419 },
420 None => {
421 self.record(|| TrieAccess::NonExisting { full_key });
422
423 return Ok(None)
424 },
425 }
426 },
427 NodeOwned::NibbledBranch(slice, children, value) => {
428 if !partial.starts_with_vec(&slice) {
429 self.record(|| TrieAccess::NonExisting { full_key });
430
431 return Ok(None)
432 }
433
434 if partial.len() == slice.len() {
435 return if let Some(value) = value.clone() {
436 drop(node);
437 load_value_owned(
438 value,
439 nibble_key.original_data_as_prefix(),
440 full_key,
441 cache,
442 self.db,
443 &mut self.recorder,
444 )
445 .map(Some)
446 } else {
447 self.record(|| TrieAccess::NonExisting { full_key });
448
449 Ok(None)
450 }
451 } else {
452 match &children[partial.at(slice.len()) as usize] {
453 Some(x) => {
454 partial = partial.mid(slice.len() + 1);
455 key_nibbles += slice.len() + 1;
456 x
457 },
458 None => {
459 self.record(|| TrieAccess::NonExisting { full_key });
460
461 return Ok(None)
462 },
463 }
464 }
465 },
466 NodeOwned::Empty => {
467 self.record(|| TrieAccess::NonExisting { full_key });
468
469 return Ok(None)
470 },
471 NodeOwned::Value(_, _) => {
472 unreachable!(
473 "`NodeOwned::Value` can not be reached by using the hash of a node. \
474 `NodeOwned::Value` is only constructed when loading a value into memory, \
475 which needs to have a different hash than any node; qed",
476 )
477 },
478 };
479
480 match next_node {
482 NodeHandleOwned::Hash(new_hash) => {
483 hash = *new_hash;
484 break
485 },
486 NodeHandleOwned::Inline(inline_node) => {
487 node = &inline_node;
488 },
489 }
490 }
491 }
492
493 Ok(None)
494 }
495
496 fn look_up_without_cache<R>(
502 mut self,
503 nibble_key: NibbleSlice,
504 full_key: &[u8],
505 load_value: impl Fn(
506 Value,
507 Prefix,
508 &[u8],
509 &dyn HashDBRef<L::Hash, DBValue>,
510 &mut Option<&mut dyn TrieRecorder<TrieHash<L>>>,
511 Q,
512 ) -> Result<R, TrieHash<L>, CError<L>>,
513 ) -> Result<Option<R>, TrieHash<L>, CError<L>> {
514 let mut partial = nibble_key;
515 let mut hash = self.hash;
516 let mut key_nibbles = 0;
517
518 for depth in 0.. {
520 let node_data = match self.db.get(&hash, nibble_key.mid(key_nibbles).left()) {
521 Some(value) => value,
522 None =>
523 return Err(Box::new(match depth {
524 0 => TrieError::InvalidStateRoot(hash),
525 _ => TrieError::IncompleteDatabase(hash),
526 })),
527 };
528
529 self.record(|| TrieAccess::EncodedNode {
530 hash,
531 encoded_node: node_data.as_slice().into(),
532 });
533
534 let mut node_data = &node_data[..];
537 loop {
538 let decoded = match L::Codec::decode(node_data) {
539 Ok(node) => node,
540 Err(e) => return Err(Box::new(TrieError::DecoderError(hash, e))),
541 };
542
543 let next_node = match decoded {
544 Node::Leaf(slice, value) =>
545 return if slice == partial {
546 load_value(
547 value,
548 nibble_key.original_data_as_prefix(),
549 full_key,
550 self.db,
551 &mut self.recorder,
552 self.query,
553 )
554 .map(Some)
555 } else {
556 self.record(|| TrieAccess::NonExisting { full_key });
557
558 Ok(None)
559 },
560 Node::Extension(slice, item) =>
561 if partial.starts_with(&slice) {
562 partial = partial.mid(slice.len());
563 key_nibbles += slice.len();
564 item
565 } else {
566 self.record(|| TrieAccess::NonExisting { full_key });
567
568 return Ok(None)
569 },
570 Node::Branch(children, value) =>
571 if partial.is_empty() {
572 return if let Some(val) = value {
573 load_value(
574 val,
575 nibble_key.original_data_as_prefix(),
576 full_key,
577 self.db,
578 &mut self.recorder,
579 self.query,
580 )
581 .map(Some)
582 } else {
583 self.record(|| TrieAccess::NonExisting { full_key });
584
585 Ok(None)
586 }
587 } else {
588 match children[partial.at(0) as usize] {
589 Some(x) => {
590 partial = partial.mid(1);
591 key_nibbles += 1;
592 x
593 },
594 None => {
595 self.record(|| TrieAccess::NonExisting { full_key });
596
597 return Ok(None)
598 },
599 }
600 },
601 Node::NibbledBranch(slice, children, value) => {
602 if !partial.starts_with(&slice) {
603 self.record(|| TrieAccess::NonExisting { full_key });
604
605 return Ok(None)
606 }
607
608 if partial.len() == slice.len() {
609 return if let Some(val) = value {
610 load_value(
611 val,
612 nibble_key.original_data_as_prefix(),
613 full_key,
614 self.db,
615 &mut self.recorder,
616 self.query,
617 )
618 .map(Some)
619 } else {
620 self.record(|| TrieAccess::NonExisting { full_key });
621
622 Ok(None)
623 }
624 } else {
625 match children[partial.at(slice.len()) as usize] {
626 Some(x) => {
627 partial = partial.mid(slice.len() + 1);
628 key_nibbles += slice.len() + 1;
629 x
630 },
631 None => {
632 self.record(|| TrieAccess::NonExisting { full_key });
633
634 return Ok(None)
635 },
636 }
637 }
638 },
639 Node::Empty => {
640 self.record(|| TrieAccess::NonExisting { full_key });
641
642 return Ok(None)
643 },
644 };
645
646 match next_node {
648 NodeHandle::Hash(data) => {
649 hash = decode_hash::<L::Hash>(data)
650 .ok_or_else(|| Box::new(TrieError::InvalidHash(hash, data.to_vec())))?;
651 break
652 },
653 NodeHandle::Inline(data) => {
654 node_data = data;
655 },
656 }
657 }
658 }
659 Ok(None)
660 }
661}