reference_trie/
substrate_like.rs

1// Copyright 2017, 2021 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//! Codec and layout configuration similar to upstream default substrate one.
16
17use super::{CodecError as Error, NodeCodec as NodeCodecT, *};
18use trie_db::node::Value;
19
20/// No extension trie with no hashed value.
21pub struct HashedValueNoExt;
22
23/// No extension trie which stores value above a static size
24/// as external node.
25pub struct HashedValueNoExtThreshold<const C: u32>;
26
27impl TrieLayout for HashedValueNoExt {
28	const USE_EXTENSION: bool = false;
29	const ALLOW_EMPTY: bool = false;
30	const MAX_INLINE_VALUE: Option<u32> = None;
31
32	type Hash = RefHasher;
33	type Codec = ReferenceNodeCodecNoExtMeta<RefHasher>;
34}
35
36impl<const C: u32> TrieLayout for HashedValueNoExtThreshold<C> {
37	const USE_EXTENSION: bool = false;
38	const ALLOW_EMPTY: bool = false;
39	const MAX_INLINE_VALUE: Option<u32> = Some(C);
40
41	type Hash = RefHasher;
42	type Codec = ReferenceNodeCodecNoExtMeta<RefHasher>;
43}
44
45/// Constants specific to encoding with external value node support.
46pub mod trie_constants {
47	const FIRST_PREFIX: u8 = 0b_00 << 6;
48	pub const NIBBLE_SIZE_BOUND: usize = u16::max_value() as usize;
49	pub const LEAF_PREFIX_MASK: u8 = 0b_01 << 6;
50	pub const BRANCH_WITHOUT_MASK: u8 = 0b_10 << 6;
51	pub const BRANCH_WITH_MASK: u8 = 0b_11 << 6;
52	pub const EMPTY_TRIE: u8 = FIRST_PREFIX | (0b_00 << 4);
53	pub const ALT_HASHING_LEAF_PREFIX_MASK: u8 = FIRST_PREFIX | (0b_1 << 5);
54	pub const ALT_HASHING_BRANCH_WITH_MASK: u8 = FIRST_PREFIX | (0b_01 << 4);
55	pub const ESCAPE_COMPACT_HEADER: u8 = EMPTY_TRIE | 0b_00_01;
56}
57
58#[derive(Default, Clone)]
59pub struct NodeCodec<H>(PhantomData<H>);
60
61impl<H: Hasher> NodeCodec<H> {
62	fn decode_plan_inner_hashed(data: &[u8]) -> Result<NodePlan, Error> {
63		let mut input = ByteSliceInput::new(data);
64
65		let header = NodeHeader::decode(&mut input)?;
66		let contains_hash = header.contains_hash_of_value();
67
68		let branch_has_value = if let NodeHeader::Branch(has_value, _) = &header {
69			*has_value
70		} else {
71			// alt_hash_branch
72			true
73		};
74
75		match header {
76			NodeHeader::Null => Ok(NodePlan::Empty),
77			NodeHeader::HashedValueBranch(nibble_count) | NodeHeader::Branch(_, nibble_count) => {
78				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
79				// check that the padding is valid (if any)
80				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
81					return Err(CodecError::from("Bad format"))
82				}
83				let partial = input.take(
84					(nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) /
85						nibble_ops::NIBBLE_PER_BYTE,
86				)?;
87				let partial_padding = nibble_ops::number_padding(nibble_count);
88				let bitmap_range = input.take(BITMAP_LENGTH)?;
89				let bitmap = Bitmap::decode(&data[bitmap_range])?;
90				let value = if branch_has_value {
91					Some(if contains_hash {
92						ValuePlan::Node(input.take(H::LENGTH)?)
93					} else {
94						let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
95						ValuePlan::Inline(input.take(count)?)
96					})
97				} else {
98					None
99				};
100				let mut children = [
101					None, None, None, None, None, None, None, None, None, None, None, None, None,
102					None, None, None,
103				];
104				for i in 0..nibble_ops::NIBBLE_LENGTH {
105					if bitmap.value_at(i) {
106						let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
107						let range = input.take(count)?;
108						children[i] = Some(if count == H::LENGTH {
109							NodeHandlePlan::Hash(range)
110						} else {
111							NodeHandlePlan::Inline(range)
112						});
113					}
114				}
115				Ok(NodePlan::NibbledBranch {
116					partial: NibbleSlicePlan::new(partial, partial_padding),
117					value,
118					children,
119				})
120			},
121			NodeHeader::HashedValueLeaf(nibble_count) | NodeHeader::Leaf(nibble_count) => {
122				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
123				// check that the padding is valid (if any)
124				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
125					return Err(CodecError::from("Bad format"))
126				}
127				let partial = input.take(
128					(nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) /
129						nibble_ops::NIBBLE_PER_BYTE,
130				)?;
131				let partial_padding = nibble_ops::number_padding(nibble_count);
132				let value = if contains_hash {
133					ValuePlan::Node(input.take(H::LENGTH)?)
134				} else {
135					let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
136					ValuePlan::Inline(input.take(count)?)
137				};
138
139				Ok(NodePlan::Leaf {
140					partial: NibbleSlicePlan::new(partial, partial_padding),
141					value,
142				})
143			},
144		}
145	}
146}
147
148impl<H> NodeCodecT for NodeCodec<H>
149where
150	H: Hasher,
151{
152	const ESCAPE_HEADER: Option<u8> = Some(trie_constants::ESCAPE_COMPACT_HEADER);
153	type Error = Error;
154	type HashOut = H::Out;
155
156	fn hashed_null_node() -> <H as Hasher>::Out {
157		H::hash(<Self as NodeCodecT>::empty_node())
158	}
159
160	fn decode_plan(data: &[u8]) -> Result<NodePlan, Self::Error> {
161		Self::decode_plan_inner_hashed(data)
162	}
163
164	fn is_empty_node(data: &[u8]) -> bool {
165		data == <Self as NodeCodecT>::empty_node()
166	}
167
168	fn empty_node() -> &'static [u8] {
169		&[trie_constants::EMPTY_TRIE]
170	}
171
172	fn leaf_node(partial: impl Iterator<Item = u8>, number_nibble: usize, value: Value) -> Vec<u8> {
173		let contains_hash = matches!(&value, Value::Node(..));
174		let mut output = if contains_hash {
175			partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueLeaf)
176		} else {
177			partial_from_iterator_encode(partial, number_nibble, NodeKind::Leaf)
178		};
179		match value {
180			Value::Inline(value) => {
181				Compact(value.len() as u32).encode_to(&mut output);
182				output.extend_from_slice(value);
183			},
184			Value::Node(hash) => {
185				debug_assert!(hash.len() == H::LENGTH);
186				output.extend_from_slice(hash);
187			},
188		}
189		output
190	}
191
192	fn extension_node(
193		_partial: impl Iterator<Item = u8>,
194		_nbnibble: usize,
195		_child: ChildReference<<H as Hasher>::Out>,
196	) -> Vec<u8> {
197		unreachable!("Codec without extension.")
198	}
199
200	fn branch_node(
201		_children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
202		_maybe_value: Option<Value>,
203	) -> Vec<u8> {
204		unreachable!("Codec without extension.")
205	}
206
207	fn branch_node_nibbled(
208		partial: impl Iterator<Item = u8>,
209		number_nibble: usize,
210		children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
211		value: Option<Value>,
212	) -> Vec<u8> {
213		let contains_hash = matches!(&value, Some(Value::Node(..)));
214		let mut output = match (&value, contains_hash) {
215			(&None, _) =>
216				partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue),
217			(_, false) =>
218				partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue),
219			(_, true) =>
220				partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueBranch),
221		};
222
223		let bitmap_index = output.len();
224		let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH];
225		(0..BITMAP_LENGTH).for_each(|_| output.push(0));
226		match value {
227			Some(Value::Inline(value)) => {
228				Compact(value.len() as u32).encode_to(&mut output);
229				output.extend_from_slice(value);
230			},
231			Some(Value::Node(hash)) => {
232				debug_assert!(hash.len() == H::LENGTH);
233				output.extend_from_slice(hash);
234			},
235			None => (),
236		}
237		Bitmap::encode(
238			children.map(|maybe_child| match maybe_child.borrow() {
239				Some(ChildReference::Hash(h)) => {
240					h.as_ref().encode_to(&mut output);
241					true
242				},
243				&Some(ChildReference::Inline(inline_data, len)) => {
244					inline_data.as_ref()[..len].encode_to(&mut output);
245					true
246				},
247				None => false,
248			}),
249			bitmap.as_mut(),
250		);
251		output[bitmap_index..bitmap_index + BITMAP_LENGTH]
252			.copy_from_slice(&bitmap[..BITMAP_LENGTH]);
253		output
254	}
255}
256
257// utils
258
259/// Encode and allocate node type header (type and size), and partial value.
260/// It uses an iterator over encoded partial bytes as input.
261fn partial_from_iterator_encode<I: Iterator<Item = u8>>(
262	partial: I,
263	nibble_count: usize,
264	node_kind: NodeKind,
265) -> Vec<u8> {
266	let nibble_count = std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count);
267
268	let mut output = Vec::with_capacity(4 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE));
269	match node_kind {
270		NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output),
271		NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output),
272		NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output),
273		NodeKind::HashedValueLeaf =>
274			NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output),
275		NodeKind::HashedValueBranch =>
276			NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output),
277	};
278	output.extend(partial);
279	output
280}
281
282/// A node header.
283#[derive(Copy, Clone, PartialEq, Eq, Debug)]
284pub(crate) enum NodeHeader {
285	Null,
286	// contains wether there is a value and nibble count
287	Branch(bool, usize),
288	// contains nibble count
289	Leaf(usize),
290	// contains nibble count.
291	HashedValueBranch(usize),
292	// contains nibble count.
293	HashedValueLeaf(usize),
294}
295
296impl NodeHeader {
297	fn contains_hash_of_value(&self) -> bool {
298		match self {
299			NodeHeader::HashedValueBranch(_) | NodeHeader::HashedValueLeaf(_) => true,
300			_ => false,
301		}
302	}
303}
304
305/// NodeHeader without content
306pub(crate) enum NodeKind {
307	Leaf,
308	BranchNoValue,
309	BranchWithValue,
310	HashedValueLeaf,
311	HashedValueBranch,
312}
313
314impl Encode for NodeHeader {
315	fn encode_to<T: Output + ?Sized>(&self, output: &mut T) {
316		match self {
317			NodeHeader::Null => output.push_byte(trie_constants::EMPTY_TRIE),
318			NodeHeader::Branch(true, nibble_count) =>
319				encode_size_and_prefix(*nibble_count, trie_constants::BRANCH_WITH_MASK, 2, output),
320			NodeHeader::Branch(false, nibble_count) => encode_size_and_prefix(
321				*nibble_count,
322				trie_constants::BRANCH_WITHOUT_MASK,
323				2,
324				output,
325			),
326			NodeHeader::Leaf(nibble_count) =>
327				encode_size_and_prefix(*nibble_count, trie_constants::LEAF_PREFIX_MASK, 2, output),
328			NodeHeader::HashedValueBranch(nibble_count) => encode_size_and_prefix(
329				*nibble_count,
330				trie_constants::ALT_HASHING_BRANCH_WITH_MASK,
331				4,
332				output,
333			),
334			NodeHeader::HashedValueLeaf(nibble_count) => encode_size_and_prefix(
335				*nibble_count,
336				trie_constants::ALT_HASHING_LEAF_PREFIX_MASK,
337				3,
338				output,
339			),
340		}
341	}
342}
343
344impl parity_scale_codec::EncodeLike for NodeHeader {}
345
346impl Decode for NodeHeader {
347	fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
348		let i = input.read_byte()?;
349		if i == trie_constants::EMPTY_TRIE {
350			return Ok(NodeHeader::Null)
351		}
352		match i & (0b11 << 6) {
353			trie_constants::LEAF_PREFIX_MASK => Ok(NodeHeader::Leaf(decode_size(i, input, 2)?)),
354			trie_constants::BRANCH_WITH_MASK =>
355				Ok(NodeHeader::Branch(true, decode_size(i, input, 2)?)),
356			trie_constants::BRANCH_WITHOUT_MASK =>
357				Ok(NodeHeader::Branch(false, decode_size(i, input, 2)?)),
358			trie_constants::EMPTY_TRIE => {
359				if i & (0b111 << 5) == trie_constants::ALT_HASHING_LEAF_PREFIX_MASK {
360					Ok(NodeHeader::HashedValueLeaf(decode_size(i, input, 3)?))
361				} else if i & (0b1111 << 4) == trie_constants::ALT_HASHING_BRANCH_WITH_MASK {
362					Ok(NodeHeader::HashedValueBranch(decode_size(i, input, 4)?))
363				} else {
364					// do not allow any special encoding
365					Err("Unallowed encoding".into())
366				}
367			},
368			_ => unreachable!(),
369		}
370	}
371}
372
373/// Returns an iterator over encoded bytes for node header and size.
374/// Size encoding allows unlimited, length inefficient, representation, but
375/// is bounded to 16 bit maximum value to avoid possible DOS.
376pub(crate) fn size_and_prefix_iterator(
377	size: usize,
378	prefix: u8,
379	prefix_mask: usize,
380) -> impl Iterator<Item = u8> {
381	let size = std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, size);
382
383	let max_value = 255u8 >> prefix_mask;
384	let l1 = std::cmp::min(max_value as usize - 1, size);
385	let (first_byte, mut rem) = if size == l1 {
386		(once(prefix + l1 as u8), 0)
387	} else {
388		(once(prefix + max_value as u8), size - l1)
389	};
390	let next_bytes = move || {
391		if rem > 0 {
392			if rem < 256 {
393				let result = rem - 1;
394				rem = 0;
395				Some(result as u8)
396			} else {
397				rem = rem.saturating_sub(255);
398				Some(255)
399			}
400		} else {
401			None
402		}
403	};
404	first_byte.chain(std::iter::from_fn(next_bytes))
405}
406
407/// Encodes size and prefix to a stream output (prefix on 2 first bit only).
408fn encode_size_and_prefix<W>(size: usize, prefix: u8, prefix_mask: usize, out: &mut W)
409where
410	W: Output + ?Sized,
411{
412	for b in size_and_prefix_iterator(size, prefix, prefix_mask) {
413		out.push_byte(b)
414	}
415}
416
417/// Decode size only from stream input and header byte.
418fn decode_size(first: u8, input: &mut impl Input, prefix_mask: usize) -> Result<usize, Error> {
419	let max_value = 255u8 >> prefix_mask;
420	let mut result = (first & max_value) as usize;
421	if result < max_value as usize {
422		return Ok(result)
423	}
424	result -= 1;
425	while result <= trie_constants::NIBBLE_SIZE_BOUND {
426		let n = input.read_byte()? as usize;
427		if n < 255 {
428			return Ok(result + n + 1)
429		}
430		result += 255;
431	}
432	Ok(trie_constants::NIBBLE_SIZE_BOUND)
433}
434
435/// Reference implementation of a `TrieStream` without extension.
436#[derive(Default, Clone)]
437pub struct ReferenceTrieStreamNoExt {
438	/// Current node buffer.
439	buffer: Vec<u8>,
440}
441
442/// Create a leaf/branch node, encoding a number of nibbles.
443fn fuse_nibbles_node<'a>(nibbles: &'a [u8], kind: NodeKind) -> impl Iterator<Item = u8> + 'a {
444	let size = std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibbles.len());
445
446	let iter_start = match kind {
447		NodeKind::Leaf => size_and_prefix_iterator(size, trie_constants::LEAF_PREFIX_MASK, 2),
448		NodeKind::BranchNoValue =>
449			size_and_prefix_iterator(size, trie_constants::BRANCH_WITHOUT_MASK, 2),
450		NodeKind::BranchWithValue =>
451			size_and_prefix_iterator(size, trie_constants::BRANCH_WITH_MASK, 2),
452		NodeKind::HashedValueLeaf =>
453			size_and_prefix_iterator(size, trie_constants::ALT_HASHING_LEAF_PREFIX_MASK, 3),
454		NodeKind::HashedValueBranch =>
455			size_and_prefix_iterator(size, trie_constants::ALT_HASHING_BRANCH_WITH_MASK, 4),
456	};
457	iter_start
458		.chain(if nibbles.len() % 2 == 1 { Some(nibbles[0]) } else { None })
459		.chain(nibbles[nibbles.len() % 2..].chunks(2).map(|ch| ch[0] << 4 | ch[1]))
460}
461
462use trie_root::Value as TrieStreamValue;
463impl TrieStream for ReferenceTrieStreamNoExt {
464	fn new() -> Self {
465		Self { buffer: Vec::new() }
466	}
467
468	fn append_empty_data(&mut self) {
469		self.buffer.push(trie_constants::EMPTY_TRIE);
470	}
471
472	fn append_leaf(&mut self, key: &[u8], value: TrieStreamValue) {
473		let kind = match &value {
474			TrieStreamValue::Inline(..) => NodeKind::Leaf,
475			TrieStreamValue::Node(..) => NodeKind::HashedValueLeaf,
476		};
477		self.buffer.extend(fuse_nibbles_node(key, kind));
478		match &value {
479			TrieStreamValue::Inline(value) => {
480				Compact(value.len() as u32).encode_to(&mut self.buffer);
481				self.buffer.extend_from_slice(value);
482			},
483			TrieStreamValue::Node(hash) => {
484				self.buffer.extend_from_slice(hash.as_slice());
485			},
486		};
487	}
488
489	fn begin_branch(
490		&mut self,
491		maybe_partial: Option<&[u8]>,
492		maybe_value: Option<TrieStreamValue>,
493		has_children: impl Iterator<Item = bool>,
494	) {
495		if let Some(partial) = maybe_partial {
496			let kind = match &maybe_value {
497				None => NodeKind::BranchNoValue,
498				Some(TrieStreamValue::Inline(..)) => NodeKind::BranchWithValue,
499				Some(TrieStreamValue::Node(..)) => NodeKind::HashedValueBranch,
500			};
501
502			self.buffer.extend(fuse_nibbles_node(partial, kind));
503			let bm = branch_node_bit_mask(has_children);
504			self.buffer.extend([bm.0, bm.1].iter());
505		} else {
506			unreachable!("trie stream codec only for no extension trie");
507		}
508		match maybe_value {
509			None => (),
510			Some(TrieStreamValue::Inline(value)) => {
511				Compact(value.len() as u32).encode_to(&mut self.buffer);
512				self.buffer.extend_from_slice(value);
513			},
514			Some(TrieStreamValue::Node(hash)) => {
515				self.buffer.extend_from_slice(hash.as_slice());
516			},
517		}
518	}
519
520	fn append_extension(&mut self, _key: &[u8]) {
521		unreachable!("trie stream codec only for no extension trie");
522	}
523
524	fn append_substream<H: Hasher>(&mut self, other: Self) {
525		let data = other.out();
526		match data.len() {
527			0..=31 => data.encode_to(&mut self.buffer),
528			_ => H::hash(&data).as_ref().encode_to(&mut self.buffer),
529		}
530	}
531
532	fn out(self) -> Vec<u8> {
533		self.buffer
534	}
535}