Skip to main content

subsoil/trie/
node_codec.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! `NodeCodec` implementation for Substrate's trie format.
8
9use super::node_header::{NodeHeader, NodeKind};
10use super::{error::Error, trie_constants};
11use alloc::{borrow::Borrow, vec::Vec};
12use codec::{Compact, Decode, Encode, Input};
13use core::{marker::PhantomData, ops::Range};
14use hash_db::Hasher;
15use trie_db::{
16	nibble_ops,
17	node::{NibbleSlicePlan, NodeHandlePlan, NodePlan, Value, ValuePlan},
18	ChildReference, NodeCodec as NodeCodecT,
19};
20
21/// Helper struct for trie node decoder. This implements `codec::Input` on a byte slice, while
22/// tracking the absolute position. This is similar to `std::io::Cursor` but does not implement
23/// `Read` and `io` are not in `core` or `alloc`.
24struct ByteSliceInput<'a> {
25	data: &'a [u8],
26	offset: usize,
27}
28
29impl<'a> ByteSliceInput<'a> {
30	fn new(data: &'a [u8]) -> Self {
31		ByteSliceInput { data, offset: 0 }
32	}
33
34	fn take(&mut self, count: usize) -> Result<Range<usize>, codec::Error> {
35		if self.offset + count > self.data.len() {
36			return Err("out of data".into());
37		}
38
39		let range = self.offset..(self.offset + count);
40		self.offset += count;
41		Ok(range)
42	}
43}
44
45impl<'a> Input for ByteSliceInput<'a> {
46	fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
47		Ok(Some(self.data.len().saturating_sub(self.offset)))
48	}
49
50	fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
51		let range = self.take(into.len())?;
52		into.copy_from_slice(&self.data[range]);
53		Ok(())
54	}
55
56	fn read_byte(&mut self) -> Result<u8, codec::Error> {
57		if self.offset + 1 > self.data.len() {
58			return Err("out of data".into());
59		}
60
61		let byte = self.data[self.offset];
62		self.offset += 1;
63		Ok(byte)
64	}
65}
66
67/// Concrete implementation of a [`NodeCodecT`] with SCALE encoding.
68///
69/// It is generic over `H` the [`Hasher`].
70#[derive(Default, Clone)]
71pub struct NodeCodec<H>(PhantomData<H>);
72
73impl<H> NodeCodecT for NodeCodec<H>
74where
75	H: Hasher,
76{
77	const ESCAPE_HEADER: Option<u8> = Some(trie_constants::ESCAPE_COMPACT_HEADER);
78	type Error = Error<H::Out>;
79	type HashOut = H::Out;
80
81	fn hashed_null_node() -> <H as Hasher>::Out {
82		H::hash(<Self as NodeCodecT>::empty_node())
83	}
84
85	fn decode_plan(data: &[u8]) -> Result<NodePlan, Self::Error> {
86		let mut input = ByteSliceInput::new(data);
87
88		let header = NodeHeader::decode(&mut input)?;
89		let contains_hash = header.contains_hash_of_value();
90
91		let branch_has_value = if let NodeHeader::Branch(has_value, _) = &header {
92			*has_value
93		} else {
94			// hashed_value_branch
95			true
96		};
97
98		match header {
99			NodeHeader::Null => Ok(NodePlan::Empty),
100			NodeHeader::HashedValueBranch(nibble_count) | NodeHeader::Branch(_, nibble_count) => {
101				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
102				// data should be at least of size offset + 1
103				if data.len() < input.offset + 1 {
104					return Err(Error::BadFormat);
105				}
106				// check that the padding is valid (if any)
107				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
108					return Err(Error::BadFormat);
109				}
110				let partial = input.take(nibble_count.div_ceil(nibble_ops::NIBBLE_PER_BYTE))?;
111				let partial_padding = nibble_ops::number_padding(nibble_count);
112				let bitmap_range = input.take(BITMAP_LENGTH)?;
113				let bitmap = Bitmap::decode(&data[bitmap_range])?;
114				let value = if branch_has_value {
115					Some(if contains_hash {
116						ValuePlan::Node(input.take(H::LENGTH)?)
117					} else {
118						let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
119						ValuePlan::Inline(input.take(count)?)
120					})
121				} else {
122					None
123				};
124				let mut children = [
125					None, None, None, None, None, None, None, None, None, None, None, None, None,
126					None, None, None,
127				];
128				for i in 0..nibble_ops::NIBBLE_LENGTH {
129					if bitmap.value_at(i) {
130						let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
131						let range = input.take(count)?;
132						children[i] = Some(if count == H::LENGTH {
133							NodeHandlePlan::Hash(range)
134						} else {
135							NodeHandlePlan::Inline(range)
136						});
137					}
138				}
139				Ok(NodePlan::NibbledBranch {
140					partial: NibbleSlicePlan::new(partial, partial_padding),
141					value,
142					children,
143				})
144			},
145			NodeHeader::HashedValueLeaf(nibble_count) | NodeHeader::Leaf(nibble_count) => {
146				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
147				// data should be at least of size offset + 1
148				if data.len() < input.offset + 1 {
149					return Err(Error::BadFormat);
150				}
151				// check that the padding is valid (if any)
152				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
153					return Err(Error::BadFormat);
154				}
155				let partial = input.take(nibble_count.div_ceil(nibble_ops::NIBBLE_PER_BYTE))?;
156				let partial_padding = nibble_ops::number_padding(nibble_count);
157				let value = if contains_hash {
158					ValuePlan::Node(input.take(H::LENGTH)?)
159				} else {
160					let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
161					ValuePlan::Inline(input.take(count)?)
162				};
163
164				Ok(NodePlan::Leaf {
165					partial: NibbleSlicePlan::new(partial, partial_padding),
166					value,
167				})
168			},
169		}
170	}
171
172	fn is_empty_node(data: &[u8]) -> bool {
173		data == <Self as NodeCodecT>::empty_node()
174	}
175
176	fn empty_node() -> &'static [u8] {
177		&[trie_constants::EMPTY_TRIE]
178	}
179
180	fn leaf_node(partial: impl Iterator<Item = u8>, number_nibble: usize, value: Value) -> Vec<u8> {
181		let contains_hash = matches!(&value, Value::Node(..));
182		let mut output = if contains_hash {
183			partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueLeaf)
184		} else {
185			partial_from_iterator_encode(partial, number_nibble, NodeKind::Leaf)
186		};
187		match value {
188			Value::Inline(value) => {
189				Compact(value.len() as u32).encode_to(&mut output);
190				output.extend_from_slice(value);
191			},
192			Value::Node(hash) => {
193				debug_assert!(hash.len() == H::LENGTH);
194				output.extend_from_slice(hash);
195			},
196		}
197		output
198	}
199
200	fn extension_node(
201		_partial: impl Iterator<Item = u8>,
202		_nbnibble: usize,
203		_child: ChildReference<<H as Hasher>::Out>,
204	) -> Vec<u8> {
205		unreachable!("No extension codec.")
206	}
207
208	fn branch_node(
209		_children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
210		_maybe_value: Option<Value>,
211	) -> Vec<u8> {
212		unreachable!("No extension codec.")
213	}
214
215	fn branch_node_nibbled(
216		partial: impl Iterator<Item = u8>,
217		number_nibble: usize,
218		children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
219		value: Option<Value>,
220	) -> Vec<u8> {
221		let contains_hash = matches!(&value, Some(Value::Node(..)));
222		let mut output = match (&value, contains_hash) {
223			(&None, _) => {
224				partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue)
225			},
226			(_, false) => {
227				partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue)
228			},
229			(_, true) => {
230				partial_from_iterator_encode(partial, number_nibble, NodeKind::HashedValueBranch)
231			},
232		};
233
234		let bitmap_index = output.len();
235		let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH];
236		(0..BITMAP_LENGTH).for_each(|_| output.push(0));
237		match value {
238			Some(Value::Inline(value)) => {
239				Compact(value.len() as u32).encode_to(&mut output);
240				output.extend_from_slice(value);
241			},
242			Some(Value::Node(hash)) => {
243				debug_assert!(hash.len() == H::LENGTH);
244				output.extend_from_slice(hash);
245			},
246			None => (),
247		}
248		Bitmap::encode(
249			children.map(|maybe_child| match maybe_child.borrow() {
250				Some(ChildReference::Hash(h)) => {
251					h.as_ref().encode_to(&mut output);
252					true
253				},
254				&Some(ChildReference::Inline(inline_data, len)) => {
255					inline_data.as_ref()[..len].encode_to(&mut output);
256					true
257				},
258				None => false,
259			}),
260			bitmap.as_mut(),
261		);
262		output[bitmap_index..bitmap_index + BITMAP_LENGTH]
263			.copy_from_slice(&bitmap[..BITMAP_LENGTH]);
264		output
265	}
266}
267
268// utils
269
270/// Encode and allocate node type header (type and size), and partial value.
271/// It uses an iterator over encoded partial bytes as input.
272fn partial_from_iterator_encode<I: Iterator<Item = u8>>(
273	partial: I,
274	nibble_count: usize,
275	node_kind: NodeKind,
276) -> Vec<u8> {
277	let mut output = Vec::with_capacity(4 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE));
278	match node_kind {
279		NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output),
280		NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output),
281		NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output),
282		NodeKind::HashedValueLeaf => {
283			NodeHeader::HashedValueLeaf(nibble_count).encode_to(&mut output)
284		},
285		NodeKind::HashedValueBranch => {
286			NodeHeader::HashedValueBranch(nibble_count).encode_to(&mut output)
287		},
288	};
289	output.extend(partial);
290	output
291}
292
293const BITMAP_LENGTH: usize = 2;
294
295/// Radix 16 trie, bitmap encoding implementation,
296/// it contains children mapping information for a branch
297/// (children presence only), it encodes into
298/// a compact bitmap encoding representation.
299pub(crate) struct Bitmap(u16);
300
301impl Bitmap {
302	pub fn decode(data: &[u8]) -> Result<Self, codec::Error> {
303		let value = u16::decode(&mut &data[..])?;
304		if value == 0 {
305			Err("Bitmap without a child.".into())
306		} else {
307			Ok(Bitmap(value))
308		}
309	}
310
311	pub fn value_at(&self, i: usize) -> bool {
312		self.0 & (1u16 << i) != 0
313	}
314
315	pub fn encode<I: Iterator<Item = bool>>(has_children: I, dest: &mut [u8]) {
316		let mut bitmap: u16 = 0;
317		let mut cursor: u16 = 1;
318		for v in has_children {
319			if v {
320				bitmap |= cursor
321			}
322			cursor <<= 1;
323		}
324		dest[0] = (bitmap % 256) as u8;
325		dest[1] = (bitmap / 256) as u8;
326	}
327}