trie_db/
iter_build.rs

1// Copyright 2017, 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version .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//! Alternative tools for working with key value ordered iterator without recursion.
16//! This is iterative implementation of `trie_root` algorithm, using `NodeCodec`
17//! implementation.
18//! See `trie_visit` function.
19
20use crate::{
21	nibble::{nibble_ops, NibbleSlice},
22	node::Value,
23	node_codec::NodeCodec,
24	rstd::{cmp::max, marker::PhantomData, vec::Vec},
25	triedbmut::ChildReference,
26	DBValue, TrieHash, TrieLayout,
27};
28use hash_db::{HashDB, Hasher, Prefix};
29
30macro_rules! exponential_out {
31	(@3, [$($inpp:expr),*]) => { exponential_out!(@2, [$($inpp,)* $($inpp),*]) };
32	(@2, [$($inpp:expr),*]) => { exponential_out!(@1, [$($inpp,)* $($inpp),*]) };
33	(@1, [$($inpp:expr),*]) => { [$($inpp,)* $($inpp),*] };
34}
35
36type CacheNode<HO> = Option<ChildReference<HO>>;
37
38#[inline(always)]
39fn new_vec_slice_buffer<HO>() -> [CacheNode<HO>; 16] {
40	exponential_out!(@3, [None, None])
41}
42
43type ArrayNode<T> = [CacheNode<TrieHash<T>>; 16];
44
45/// Struct containing iteration cache, can be at most the length of the lowest nibble.
46///
47/// Note that it is not memory optimal (all depth are allocated even if some are empty due
48/// to node partial).
49/// Three field are used, a cache over the children, an optional associated value and the depth.
50struct CacheAccum<T: TrieLayout, V>(Vec<(ArrayNode<T>, Option<V>, usize)>);
51
52/// Initially allocated cache depth.
53const INITIAL_DEPTH: usize = 10;
54
55impl<T, V> CacheAccum<T, V>
56where
57	T: TrieLayout,
58	V: AsRef<[u8]>,
59{
60	fn new() -> Self {
61		let v = Vec::with_capacity(INITIAL_DEPTH);
62		CacheAccum(v)
63	}
64
65	#[inline(always)]
66	fn set_cache_value(&mut self, depth: usize, value: Option<V>) {
67		if self.0.is_empty() || self.0[self.0.len() - 1].2 < depth {
68			self.0.push((new_vec_slice_buffer(), None, depth));
69		}
70		let last = self.0.len() - 1;
71		debug_assert!(self.0[last].2 <= depth);
72		self.0[last].1 = value;
73	}
74
75	#[inline(always)]
76	fn set_node(&mut self, depth: usize, nibble_index: usize, node: CacheNode<TrieHash<T>>) {
77		if self.0.is_empty() || self.0[self.0.len() - 1].2 < depth {
78			self.0.push((new_vec_slice_buffer(), None, depth));
79		}
80
81		let last = self.0.len() - 1;
82		debug_assert!(self.0[last].2 == depth);
83
84		self.0[last].0.as_mut()[nibble_index] = node;
85	}
86
87	#[inline(always)]
88	fn last_depth(&self) -> usize {
89		let ix = self.0.len();
90		if ix > 0 {
91			let last = ix - 1;
92			self.0[last].2
93		} else {
94			0
95		}
96	}
97
98	#[inline(always)]
99	fn last_last_depth(&self) -> usize {
100		let ix = self.0.len();
101		if ix > 1 {
102			let last = ix - 2;
103			self.0[last].2
104		} else {
105			0
106		}
107	}
108
109	#[inline(always)]
110	fn is_empty(&self) -> bool {
111		self.0.is_empty()
112	}
113	#[inline(always)]
114	fn is_one(&self) -> bool {
115		self.0.len() == 1
116	}
117
118	fn flush_value(
119		&mut self,
120		callback: &mut impl ProcessEncodedNode<TrieHash<T>>,
121		target_depth: usize,
122		(k2, v2): &(impl AsRef<[u8]>, impl AsRef<[u8]>),
123	) {
124		let nibble_value = nibble_ops::left_nibble_at(&k2.as_ref()[..], target_depth);
125		// is it a branch value (two candidate same ix)
126		let nkey = NibbleSlice::new_offset(&k2.as_ref()[..], target_depth + 1);
127		let pr = NibbleSlice::new_offset(
128			&k2.as_ref()[..],
129			k2.as_ref().len() * nibble_ops::NIBBLE_PER_BYTE - nkey.len(),
130		);
131
132		let hashed;
133		let value = if let Some(value) = Value::new_inline(v2.as_ref(), T::MAX_INLINE_VALUE) {
134			value
135		} else {
136			hashed = callback.process_inner_hashed_value((k2.as_ref(), None), v2.as_ref());
137			Value::Node(hashed.as_ref())
138		};
139		let encoded = T::Codec::leaf_node(nkey.right_iter(), nkey.len(), value);
140		let hash = callback.process(pr.left(), encoded, false);
141
142		// insert hash in branch (first level branch only at this point)
143		self.set_node(target_depth, nibble_value as usize, Some(hash));
144	}
145
146	fn flush_branch(
147		&mut self,
148		callback: &mut impl ProcessEncodedNode<TrieHash<T>>,
149		ref_branch: impl AsRef<[u8]> + Ord,
150		new_depth: usize,
151		is_last: bool,
152	) {
153		while self.last_depth() > new_depth || is_last && !self.is_empty() {
154			let lix = self.last_depth();
155			let llix = max(self.last_last_depth(), new_depth);
156
157			let (offset, slice_size, is_root) = if llix == 0 && is_last && self.is_one() {
158				// branch root
159				(llix, lix - llix, true)
160			} else {
161				(llix + 1, lix - llix - 1, false)
162			};
163			let nkey = if slice_size > 0 { Some((offset, slice_size)) } else { None };
164
165			let h = if T::USE_EXTENSION {
166				self.standard_extension(&ref_branch.as_ref()[..], callback, lix, is_root, nkey)
167			} else {
168				// encode branch
169				self.no_extension(&ref_branch.as_ref()[..], callback, lix, is_root, nkey)
170			};
171			if !is_root {
172				// put hash in parent
173				let nibble: u8 = nibble_ops::left_nibble_at(&ref_branch.as_ref()[..], llix);
174				self.set_node(llix, nibble as usize, Some(h));
175			}
176		}
177	}
178
179	#[inline(always)]
180	fn standard_extension(
181		&mut self,
182		key_branch: &[u8],
183		callback: &mut impl ProcessEncodedNode<TrieHash<T>>,
184		branch_d: usize,
185		is_root: bool,
186		nkey: Option<(usize, usize)>,
187	) -> ChildReference<TrieHash<T>> {
188		let last = self.0.len() - 1;
189		assert_eq!(self.0[last].2, branch_d);
190
191		let (children, v, depth) = self.0.pop().expect("checked");
192
193		debug_assert!(branch_d == depth);
194		let pr = NibbleSlice::new_offset(&key_branch, branch_d);
195
196		let hashed;
197		let value = if let Some(v) = v.as_ref() {
198			Some(if let Some(value) = Value::new_inline(v.as_ref(), T::MAX_INLINE_VALUE) {
199				value
200			} else {
201				let mut prefix = NibbleSlice::new_offset(&key_branch, 0);
202				prefix.advance(branch_d);
203				hashed = callback.process_inner_hashed_value(prefix.left(), v.as_ref());
204				Value::Node(hashed.as_ref())
205			})
206		} else {
207			None
208		};
209
210		// encode branch
211		let encoded = T::Codec::branch_node(children.iter(), value);
212		let branch_hash = callback.process(pr.left(), encoded, is_root && nkey.is_none());
213
214		if let Some(nkeyix) = nkey {
215			let pr = NibbleSlice::new_offset(&key_branch, nkeyix.0);
216			let nib = pr.right_range_iter(nkeyix.1);
217			let encoded = T::Codec::extension_node(nib, nkeyix.1, branch_hash);
218			callback.process(pr.left(), encoded, is_root)
219		} else {
220			branch_hash
221		}
222	}
223
224	#[inline(always)]
225	fn no_extension(
226		&mut self,
227		key_branch: &[u8],
228		callback: &mut impl ProcessEncodedNode<TrieHash<T>>,
229		branch_d: usize,
230		is_root: bool,
231		nkey: Option<(usize, usize)>,
232	) -> ChildReference<TrieHash<T>> {
233		let (children, v, depth) = self.0.pop().expect("checked");
234
235		debug_assert!(branch_d == depth);
236		// encode branch
237		let nkeyix = nkey.unwrap_or((branch_d, 0));
238		let pr = NibbleSlice::new_offset(&key_branch, nkeyix.0);
239		let hashed;
240		let value = if let Some(v) = v.as_ref() {
241			Some(if let Some(value) = Value::new_inline(v.as_ref(), T::MAX_INLINE_VALUE) {
242				value
243			} else {
244				let mut prefix = NibbleSlice::new_offset(&key_branch, 0);
245				prefix.advance(branch_d);
246				hashed = callback.process_inner_hashed_value(prefix.left(), v.as_ref());
247				Value::Node(hashed.as_ref())
248			})
249		} else {
250			None
251		};
252
253		let encoded = T::Codec::branch_node_nibbled(
254			pr.right_range_iter(nkeyix.1),
255			nkeyix.1,
256			children.iter(),
257			value,
258		);
259		callback.process(pr.left(), encoded, is_root)
260	}
261}
262
263/// Function visiting trie from key value inputs with a `ProccessEncodedNode` callback.
264/// This is the main entry point of this module.
265/// Calls to each node occurs ordered by byte key value but with longest keys first (from node to
266/// branch to root), this differs from standard byte array ordering a bit.
267pub fn trie_visit<T, I, A, B, F>(input: I, callback: &mut F)
268where
269	T: TrieLayout,
270	I: IntoIterator<Item = (A, B)>,
271	A: AsRef<[u8]> + Ord,
272	B: AsRef<[u8]>,
273	F: ProcessEncodedNode<TrieHash<T>>,
274{
275	let mut depth_queue = CacheAccum::<T, B>::new();
276	// compare iter ordering
277	let mut iter_input = input.into_iter();
278	if let Some(mut previous_value) = iter_input.next() {
279		// depth of last item
280		let mut last_depth = 0;
281
282		let mut single = true;
283		for (k, v) in iter_input {
284			single = false;
285			let common_depth =
286				nibble_ops::biggest_depth(&previous_value.0.as_ref()[..], &k.as_ref()[..]);
287			// 0 is a reserved value : could use option
288			let depth_item = common_depth;
289			if common_depth == previous_value.0.as_ref().len() * nibble_ops::NIBBLE_PER_BYTE {
290				// the new key include the previous one : branch value case
291				// just stored value at branch depth
292				depth_queue.set_cache_value(common_depth, Some(previous_value.1));
293			} else if depth_item >= last_depth {
294				// put previous with next (common branch previous value can be flush)
295				depth_queue.flush_value(callback, depth_item, &previous_value);
296			} else if depth_item < last_depth {
297				// do not put with next, previous is last of a branch
298				depth_queue.flush_value(callback, last_depth, &previous_value);
299				let ref_branches = previous_value.0;
300				depth_queue.flush_branch(callback, ref_branches, depth_item, false);
301			}
302
303			previous_value = (k, v);
304			last_depth = depth_item;
305		}
306		// last pendings
307		if single {
308			// one single element corner case
309			let (k2, v2) = previous_value;
310			let nkey = NibbleSlice::new_offset(&k2.as_ref()[..], last_depth);
311			let pr = NibbleSlice::new_offset(
312				&k2.as_ref()[..],
313				k2.as_ref().len() * nibble_ops::NIBBLE_PER_BYTE - nkey.len(),
314			);
315
316			let hashed;
317			let value = if let Some(value) = Value::new_inline(v2.as_ref(), T::MAX_INLINE_VALUE) {
318				value
319			} else {
320				hashed = callback.process_inner_hashed_value((k2.as_ref(), None), v2.as_ref());
321				Value::Node(hashed.as_ref())
322			};
323
324			let encoded = T::Codec::leaf_node(nkey.right_iter(), nkey.len(), value);
325			callback.process(pr.left(), encoded, true);
326		} else {
327			depth_queue.flush_value(callback, last_depth, &previous_value);
328			let ref_branches = previous_value.0;
329			depth_queue.flush_branch(callback, ref_branches, 0, true);
330		}
331	} else {
332		// nothing null root corner case
333		callback.process(hash_db::EMPTY_PREFIX, T::Codec::empty_node().to_vec(), true);
334	}
335}
336
337/// Visitor trait to implement when using `trie_visit`.
338pub trait ProcessEncodedNode<HO> {
339	/// Function call with prefix, encoded value and a boolean indicating if the
340	/// node is the root for each node of the trie.
341	///
342	/// Note that the returned value can change depending on implementation,
343	/// but usually it should be the Hash of encoded node.
344	/// This is not something direcly related to encoding but is here for
345	/// optimisation purpose (builder hash_db does return this value).
346	fn process(
347		&mut self,
348		prefix: Prefix,
349		encoded_node: Vec<u8>,
350		is_root: bool,
351	) -> ChildReference<HO>;
352
353	/// Callback for hashed value in encoded node.
354	fn process_inner_hashed_value(&mut self, prefix: Prefix, value: &[u8]) -> HO;
355}
356
357/// Get trie root and insert visited node in a hash_db.
358/// As for all `ProcessEncodedNode` implementation, it
359/// is only for full trie parsing (not existing trie).
360pub struct TrieBuilder<'a, T: TrieLayout, DB> {
361	db: &'a mut DB,
362	pub root: Option<TrieHash<T>>,
363}
364
365impl<'a, T: TrieLayout, DB> TrieBuilder<'a, T, DB> {
366	pub fn new(db: &'a mut DB) -> Self {
367		TrieBuilder { db, root: None }
368	}
369}
370
371impl<'a, T, DB> ProcessEncodedNode<TrieHash<T>> for TrieBuilder<'a, T, DB>
372where
373	T: TrieLayout,
374	DB: HashDB<T::Hash, DBValue>,
375{
376	fn process(
377		&mut self,
378		prefix: Prefix,
379		encoded_node: Vec<u8>,
380		is_root: bool,
381	) -> ChildReference<TrieHash<T>> {
382		let len = encoded_node.len();
383		if !is_root && len < <T::Hash as Hasher>::LENGTH {
384			let mut h = <<T::Hash as Hasher>::Out as Default>::default();
385			h.as_mut()[..len].copy_from_slice(&encoded_node[..len]);
386
387			return ChildReference::Inline(h, len)
388		}
389		let hash = self.db.insert(prefix, &encoded_node[..]);
390		if is_root {
391			self.root = Some(hash);
392		};
393		ChildReference::Hash(hash)
394	}
395
396	fn process_inner_hashed_value(&mut self, prefix: Prefix, value: &[u8]) -> TrieHash<T> {
397		self.db.insert(prefix, value)
398	}
399}
400
401/// Calculate the trie root of the trie.
402pub struct TrieRoot<T: TrieLayout> {
403	/// The resulting root.
404	pub root: Option<TrieHash<T>>,
405}
406
407impl<T: TrieLayout> Default for TrieRoot<T> {
408	fn default() -> Self {
409		TrieRoot { root: None }
410	}
411}
412
413impl<T: TrieLayout> ProcessEncodedNode<TrieHash<T>> for TrieRoot<T> {
414	fn process(
415		&mut self,
416		_: Prefix,
417		encoded_node: Vec<u8>,
418		is_root: bool,
419	) -> ChildReference<TrieHash<T>> {
420		let len = encoded_node.len();
421		if !is_root && len < <T::Hash as Hasher>::LENGTH {
422			let mut h = <<T::Hash as Hasher>::Out as Default>::default();
423			h.as_mut()[..len].copy_from_slice(&encoded_node[..len]);
424
425			return ChildReference::Inline(h, len)
426		}
427		let hash = <T::Hash as Hasher>::hash(encoded_node.as_slice());
428		if is_root {
429			self.root = Some(hash);
430		};
431		ChildReference::Hash(hash)
432	}
433
434	fn process_inner_hashed_value(&mut self, _prefix: Prefix, value: &[u8]) -> TrieHash<T> {
435		<T::Hash as Hasher>::hash(value)
436	}
437}
438
439/// Get the trie root node encoding.
440pub struct TrieRootUnhashed<T: TrieLayout> {
441	/// The resulting encoded root.
442	pub root: Option<Vec<u8>>,
443	_ph: PhantomData<T>,
444}
445
446impl<T: TrieLayout> Default for TrieRootUnhashed<T> {
447	fn default() -> Self {
448		TrieRootUnhashed { root: None, _ph: PhantomData }
449	}
450}
451
452#[cfg(feature = "std")]
453/// Calculate the trie root of the trie.
454/// Print a debug trace.
455pub struct TrieRootPrint<T: TrieLayout> {
456	/// The resulting root.
457	pub root: Option<TrieHash<T>>,
458	_ph: PhantomData<T>,
459}
460
461#[cfg(feature = "std")]
462impl<T: TrieLayout> Default for TrieRootPrint<T> {
463	fn default() -> Self {
464		TrieRootPrint { root: None, _ph: PhantomData }
465	}
466}
467
468#[cfg(feature = "std")]
469impl<T: TrieLayout> ProcessEncodedNode<TrieHash<T>> for TrieRootPrint<T> {
470	fn process(
471		&mut self,
472		p: Prefix,
473		encoded_node: Vec<u8>,
474		is_root: bool,
475	) -> ChildReference<TrieHash<T>> {
476		println!("Encoded node: {:x?}", &encoded_node);
477		println!("	with prefix: {:x?}", &p);
478		let len = encoded_node.len();
479		if !is_root && len < <T::Hash as Hasher>::LENGTH {
480			let mut h = <<T::Hash as Hasher>::Out as Default>::default();
481			h.as_mut()[..len].copy_from_slice(&encoded_node[..len]);
482
483			println!("	inline len {}", len);
484			return ChildReference::Inline(h, len)
485		}
486		let hash = <T::Hash as Hasher>::hash(encoded_node.as_slice());
487		if is_root {
488			self.root = Some(hash);
489		};
490		println!("	hashed to {:x?}", hash.as_ref());
491		ChildReference::Hash(hash)
492	}
493
494	fn process_inner_hashed_value(&mut self, _prefix: Prefix, value: &[u8]) -> TrieHash<T> {
495		println!("Hashed node: {:x?}", &value);
496		<T::Hash as Hasher>::hash(value)
497	}
498}
499
500impl<T: TrieLayout> ProcessEncodedNode<TrieHash<T>> for TrieRootUnhashed<T> {
501	fn process(
502		&mut self,
503		_: Prefix,
504		encoded_node: Vec<u8>,
505		is_root: bool,
506	) -> ChildReference<<T::Hash as Hasher>::Out> {
507		let len = encoded_node.len();
508		if !is_root && len < <T::Hash as Hasher>::LENGTH {
509			let mut h = <<T::Hash as Hasher>::Out as Default>::default();
510			h.as_mut()[..len].copy_from_slice(&encoded_node[..len]);
511
512			return ChildReference::Inline(h, len)
513		}
514		let hash = <T::Hash as Hasher>::hash(encoded_node.as_slice());
515
516		if is_root {
517			self.root = Some(encoded_node);
518		};
519		ChildReference::Hash(hash)
520	}
521
522	fn process_inner_hashed_value(&mut self, _prefix: Prefix, value: &[u8]) -> TrieHash<T> {
523		<T::Hash as Hasher>::hash(value)
524	}
525}