trie_root/
lib.rs

1// Copyright 2017, 2020 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//! Generates trie root.
16//!
17//! This module should be used to generate trie root hash.
18
19#![cfg_attr(not(feature = "std"), no_std)]
20
21#[cfg(not(feature = "std"))]
22extern crate alloc;
23
24#[cfg(feature = "std")]
25mod rstd {
26	pub use std::{
27		cmp,
28		collections::{BTreeMap, VecDeque},
29		vec::Vec,
30	};
31}
32
33#[cfg(not(feature = "std"))]
34mod rstd {
35	pub use alloc::{
36		collections::{BTreeMap, VecDeque},
37		vec::Vec,
38	};
39	pub use core::cmp;
40}
41
42use self::rstd::*;
43
44pub use hash_db::Hasher;
45
46/// Different possible value to use for node encoding.
47#[derive(Clone)]
48pub enum Value<'a> {
49	/// Contains a full value.
50	Inline(&'a [u8]),
51	/// Contains hash of a value.
52	Node(Vec<u8>),
53}
54
55impl<'a> Value<'a> {
56	fn new<H: Hasher>(value: &'a [u8], threshold: Option<u32>) -> Value<'a> {
57		if let Some(threshold) = threshold {
58			if value.len() >= threshold as usize {
59				Value::Node(H::hash(value).as_ref().to_vec())
60			} else {
61				Value::Inline(value)
62			}
63		} else {
64			Value::Inline(value)
65		}
66	}
67}
68
69/// Byte-stream oriented trait for constructing closed-form tries.
70pub trait TrieStream {
71	/// Construct a new `TrieStream`
72	fn new() -> Self;
73	/// Append an Empty node
74	fn append_empty_data(&mut self);
75	/// Start a new Branch node, possibly with a value; takes a list indicating
76	/// which slots in the Branch node has further child nodes.
77	fn begin_branch(
78		&mut self,
79		maybe_key: Option<&[u8]>,
80		maybe_value: Option<Value>,
81		has_children: impl Iterator<Item = bool>,
82	);
83	/// Append an empty child node. Optional.
84	fn append_empty_child(&mut self) {}
85	/// Wrap up a Branch node portion of a `TrieStream` and append the value
86	/// stored on the Branch (if any).
87	fn end_branch(&mut self, _value: Option<Value>) {}
88	/// Append a Leaf node
89	fn append_leaf(&mut self, key: &[u8], value: Value);
90	/// Append an Extension node
91	fn append_extension(&mut self, key: &[u8]);
92	/// Append a Branch of Extension substream
93	fn append_substream<H: Hasher>(&mut self, other: Self);
94	/// Return the finished `TrieStream` as a vector of bytes.
95	fn out(self) -> Vec<u8>;
96}
97
98fn shared_prefix_length<T: Eq>(first: &[T], second: &[T]) -> usize {
99	first
100		.iter()
101		.zip(second.iter())
102		.position(|(f, s)| f != s)
103		.unwrap_or_else(|| cmp::min(first.len(), second.len()))
104}
105
106/// Generates a trie root hash for a vector of key-value tuples
107///
108/// ```ignore
109/// use hex_literal::hex;
110/// use trie_root::trie_root;
111/// use reference_trie::ReferenceTrieStream;
112/// use keccak_hasher::KeccakHasher;
113///
114/// let v = vec![
115///     ("doe", "reindeer"),
116///     ("dog", "puppy"),
117///     ("dogglesworth", "cat"),
118/// ];
119///
120/// let root = hex!["0807d5393ae7f349481063ebb5dbaf6bda58db282a385ca97f37dccba717cb79"];
121/// assert_eq!(trie_root::<KeccakHasher, ReferenceTrieStream, _, _, _>(v), root);
122/// ```
123pub fn trie_root<H, S, I, A, B>(input: I, threshold: Option<u32>) -> H::Out
124where
125	I: IntoIterator<Item = (A, B)>,
126	A: AsRef<[u8]> + Ord,
127	B: AsRef<[u8]>,
128	H: Hasher,
129	S: TrieStream,
130{
131	trie_root_inner::<H, S, I, A, B>(input, false, threshold)
132}
133
134fn trie_root_inner<H, S, I, A, B>(input: I, no_extension: bool, threshold: Option<u32>) -> H::Out
135where
136	I: IntoIterator<Item = (A, B)>,
137	A: AsRef<[u8]> + Ord,
138	B: AsRef<[u8]>,
139	H: Hasher,
140	S: TrieStream,
141{
142	// first put elements into btree to sort them and to remove duplicates
143	let input = input.into_iter().collect::<BTreeMap<_, _>>();
144
145	// convert to nibbles
146	let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
147	let mut lens = Vec::with_capacity(input.len() + 1);
148	lens.push(0);
149	for k in input.keys() {
150		for &b in k.as_ref() {
151			nibbles.push(b >> 4);
152			nibbles.push(b & 0x0F);
153		}
154		lens.push(nibbles.len());
155	}
156
157	// then move them to a vector
158	let input = input
159		.into_iter()
160		.zip(lens.windows(2))
161		.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
162		.collect::<Vec<_>>();
163
164	let mut stream = S::new();
165	build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension, threshold);
166	H::hash(&stream.out())
167}
168
169/// Variant of `trie_root` for patricia trie without extension node.
170/// See [`trie_root`].
171pub fn trie_root_no_extension<H, S, I, A, B>(input: I, threshold: Option<u32>) -> H::Out
172where
173	I: IntoIterator<Item = (A, B)>,
174	A: AsRef<[u8]> + Ord,
175	B: AsRef<[u8]>,
176	H: Hasher,
177	S: TrieStream,
178{
179	trie_root_inner::<H, S, I, A, B>(input, true, threshold)
180}
181
182//#[cfg(test)]	// consider feature="std"
183/// Method similar to `trie_root` but returning the root encoded
184/// node instead of its hash.
185/// Mainly use for testing or debugging.
186pub fn unhashed_trie<H, S, I, A, B>(input: I, threshold: Option<u32>) -> Vec<u8>
187where
188	I: IntoIterator<Item = (A, B)>,
189	A: AsRef<[u8]> + Ord,
190	B: AsRef<[u8]>,
191	H: Hasher,
192	S: TrieStream,
193{
194	unhashed_trie_inner::<H, S, I, A, B>(input, false, threshold)
195}
196
197fn unhashed_trie_inner<H, S, I, A, B>(
198	input: I,
199	no_extension: bool,
200	threshold: Option<u32>,
201) -> Vec<u8>
202where
203	I: IntoIterator<Item = (A, B)>,
204	A: AsRef<[u8]> + Ord,
205	B: AsRef<[u8]>,
206	H: Hasher,
207	S: TrieStream,
208{
209	// first put elements into btree to sort them and to remove duplicates
210	let input = input.into_iter().collect::<BTreeMap<_, _>>();
211
212	let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
213	let mut lens = Vec::with_capacity(input.len() + 1);
214	lens.push(0);
215	for k in input.keys() {
216		for &b in k.as_ref() {
217			nibbles.push(b >> 4);
218			nibbles.push(b & 0x0F);
219		}
220		lens.push(nibbles.len());
221	}
222
223	// then move them to a vector
224	let input = input
225		.into_iter()
226		.zip(lens.windows(2))
227		.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
228		.collect::<Vec<_>>();
229
230	let mut stream = S::new();
231	build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension, threshold);
232	stream.out()
233}
234
235/// Variant of `unhashed_trie` for patricia trie without extension node.
236/// See [`unhashed_trie`].
237pub fn unhashed_trie_no_extension<H, S, I, A, B>(input: I, threshold: Option<u32>) -> Vec<u8>
238where
239	I: IntoIterator<Item = (A, B)>,
240	A: AsRef<[u8]> + Ord,
241	B: AsRef<[u8]>,
242	H: Hasher,
243	S: TrieStream,
244{
245	unhashed_trie_inner::<H, S, I, A, B>(input, true, threshold)
246}
247
248/// Generates a key-hashed (secure) trie root hash for a vector of key-value tuples.
249///
250/// ```ignore
251/// use hex_literal::hex;
252/// use trie_root::sec_trie_root;
253/// use keccak_hasher::KeccakHasher;
254/// use reference_trie::ReferenceTrieStream;
255///
256/// let v = vec![
257/// 	("doe", "reindeer"),
258/// 	("dog", "puppy"),
259/// 	("dogglesworth", "cat"),
260/// ];
261///
262/// let root = hex!["d6e02b2bd48aa04fd2ad87cfac1144a29ca7f7dc60f4526c7b7040763abe3d43"];
263/// assert_eq!(sec_trie_root::<KeccakHasher, ReferenceTrieStream, _, _, _>(v), root);
264/// ```
265pub fn sec_trie_root<H, S, I, A, B>(input: I, threshold: Option<u32>) -> H::Out
266where
267	I: IntoIterator<Item = (A, B)>,
268	A: AsRef<[u8]>,
269	B: AsRef<[u8]>,
270	H: Hasher,
271	H::Out: Ord,
272	S: TrieStream,
273{
274	trie_root::<H, S, _, _, _>(input.into_iter().map(|(k, v)| (H::hash(k.as_ref()), v)), threshold)
275}
276
277/// Takes a slice of key/value tuples where the key is a slice of nibbles
278/// and encodes it into the provided `Stream`.
279fn build_trie<H, S, A, B>(
280	input: &[(A, B)],
281	cursor: usize,
282	stream: &mut S,
283	no_extension: bool,
284	threshold: Option<u32>,
285) where
286	A: AsRef<[u8]>,
287	B: AsRef<[u8]>,
288	H: Hasher,
289	S: TrieStream,
290{
291	match input.len() {
292		// No input, just append empty data.
293		0 => stream.append_empty_data(),
294		// Leaf node; append the remainder of the key and the value. Done.
295		1 => {
296			let value = Value::new::<H>(input[0].1.as_ref(), threshold);
297			stream.append_leaf(&input[0].0.as_ref()[cursor..], value)
298		},
299		// We have multiple items in the input. Figure out if we should add an
300		// extension node or a branch node.
301		_ => {
302			let (key, value) = (&input[0].0.as_ref(), input[0].1.as_ref());
303			// Count the number of nibbles in the other elements that are
304			// shared with the first key.
305			// e.g. input = [ [1'7'3'10'12'13], [1'7'3'], [1'7'7'8'9'] ] => [1'7'] is common => 2
306			let shared_nibble_count = input.iter().skip(1).fold(key.len(), |acc, &(ref k, _)| {
307				cmp::min(shared_prefix_length(key, k.as_ref()), acc)
308			});
309			// Add an extension node if the number of shared nibbles is greater
310			// than what we saw on the last call (`cursor`): append the new part
311			// of the path then recursively append the remainder of all items
312			// who had this partial key.
313			let (cursor, o_branch_slice) = if no_extension {
314				if shared_nibble_count > cursor {
315					(shared_nibble_count, Some(&key[cursor..shared_nibble_count]))
316				} else {
317					(cursor, Some(&key[0..0]))
318				}
319			} else if shared_nibble_count > cursor {
320				stream.append_extension(&key[cursor..shared_nibble_count]);
321				build_trie_trampoline::<H, _, _, _>(
322					input,
323					shared_nibble_count,
324					stream,
325					no_extension,
326					threshold,
327				);
328				return
329			} else {
330				(cursor, None)
331			};
332
333			// We'll be adding a branch node because the path is as long as it gets.
334			// First we need to figure out what entries this branch node will have...
335
336			// We have a a value for exactly this key. Branch node will have a value
337			// attached to it.
338			let value = if cursor == key.len() { Some(value) } else { None };
339
340			// We need to know how many key nibbles each of the children account for.
341			let mut shared_nibble_counts = [0usize; 16];
342			{
343				// If the Branch node has a value then the first of the input keys
344				// is exactly the key for that value and we don't care about it
345				// when finding shared nibbles for our child nodes. (We know it's
346				// the first of the input keys, because the input is sorted)
347				let mut begin = match value {
348					None => 0,
349					_ => 1,
350				};
351				for i in 0..16 {
352					shared_nibble_counts[i] = input[begin..]
353						.iter()
354						.take_while(|(k, _)| k.as_ref()[cursor] == i as u8)
355						.count();
356					begin += shared_nibble_counts[i];
357				}
358			}
359
360			// Put out the node header:
361			let value = value.map(|v| Value::new::<H>(v, threshold));
362			stream.begin_branch(
363				o_branch_slice,
364				value.clone(),
365				shared_nibble_counts.iter().map(|&n| n > 0),
366			);
367
368			// Fill in each slot in the branch node. We don't need to bother with empty slots
369			// since they were registered in the header.
370			let mut begin = match value {
371				None => 0,
372				_ => 1,
373			};
374			for &count in &shared_nibble_counts {
375				if count > 0 {
376					build_trie_trampoline::<H, S, _, _>(
377						&input[begin..(begin + count)],
378						cursor + 1,
379						stream,
380						no_extension,
381						threshold.clone(),
382					);
383					begin += count;
384				} else {
385					stream.append_empty_child();
386				}
387			}
388
389			stream.end_branch(value);
390		},
391	}
392}
393
394fn build_trie_trampoline<H, S, A, B>(
395	input: &[(A, B)],
396	cursor: usize,
397	stream: &mut S,
398	no_extension: bool,
399	threshold: Option<u32>,
400) where
401	A: AsRef<[u8]>,
402	B: AsRef<[u8]>,
403	H: Hasher,
404	S: TrieStream,
405{
406	let mut substream = S::new();
407	build_trie::<H, _, _, _>(input, cursor, &mut substream, no_extension, threshold);
408	stream.append_substream::<H>(substream);
409}