Skip to main content

trie_db/
lookup.rs

1// Copyright 2017, 2018 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
15//! Trie lookup via HashDB.
16
17use 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
27/// Trie lookup helper object.
28pub struct Lookup<'a, 'cache, L: TrieLayout, Q: Query<L::Hash>> {
29	/// database to query from.
30	pub db: &'a dyn HashDBRef<L::Hash, DBValue>,
31	/// Query object to record nodes and transform data.
32	pub query: Q,
33	/// Hash to start at
34	pub hash: TrieHash<L>,
35	/// Optional cache that should be used to speed up the lookup.
36	pub cache: Option<&'cache mut dyn TrieCache<L::Codec>>,
37	/// Optional recorder that will be called to record all trie accesses.
38	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	/// Load the given value.
47	///
48	/// This will access the `db` if the value is not already in memory, but then it will put it
49	/// into the given `cache` as `NodeOwned::Value`.
50	///
51	/// Returns the bytes representing the value.
52	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	/// Load the given value.
83	///
84	/// This will access the `db` if the value is not already in memory, but then it will put it
85	/// into the given `cache` as `NodeOwned::Value`.
86	///
87	/// Returns the bytes representing the value and its hash.
88	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	/// Look up the given `nibble_key`.
138	///
139	/// If the value is found, it will be passed to the given function to decode or copy.
140	///
141	/// The given `full_key` should be the full key to the data that is requested. This will
142	/// be used when there is a cache to potentially speed up the lookup.
143	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	/// Look up the value hash for the given `nibble_key`.
155	///
156	/// The given `full_key` should be the full key to the data that is requested. This will
157	/// be used when there is a cache to potentially speed up the lookup.
158	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	/// Look up the value hash for the given key.
187	///
188	/// It uses the given cache to speed-up lookups.
189	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			// Check if the recorder has the trie nodes already recorded for this key.
199			.map(|r| !r.trie_nodes_recorded_for_key(full_key).is_none())
200			// If there is no recorder, we can always use the value cache.
201			.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	/// Look up the given key. If the value is found, it will be passed to the given
239	/// function to decode or copy.
240	///
241	/// It uses the given cache to speed-up lookups.
242	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			// If we already have the trie nodes recorded up to the value, we are allowed
253			// to use the value cache.
254			Some(RecordedForKey::Value) | None => (true, false),
255			// If we only have recorded the hash, we are allowed to use the value cache, but
256			// we may need to have the value recorded.
257			Some(RecordedForKey::Hash) => (true, true),
258			// As we don't allow the value cache, the second value can be actually anything.
259			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					// If we only have the hash cached, this can only be a value node.
283					// For inline nodes we cache them directly as `CachedValue::Existing`.
284					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					// inline is either when no limit defined or when content
299					// is less than the limit.
300					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						// As a value is only raw data, we can directly record it.
304						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	/// When modifying any logic inside this function, you also need to do the same in
322	/// [`Self::lookup_without_cache`].
323	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		// this loop iterates through non-inline nodes.
342		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			// this loop iterates through all inline children (usually max 1)
364			// without incrementing the depth.
365			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				// check if new node data is inline or hash.
481				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	/// Look up the given key. If the value is found, it will be passed to the given
497	/// function to decode or copy.
498	///
499	/// When modifying any logic inside this function, you also need to do the same in
500	/// [`Self::lookup_with_cache_internal`].
501	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		// this loop iterates through non-inline nodes.
519		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			// this loop iterates through all inline children (usually max 1)
535			// without incrementing the depth.
536			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				// check if new node data is inline or hash.
647				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}