tp_trie/
node_codec.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2015-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! `NodeCodec` implementation for Tetcore's trie format.
19
20use tetcore_std::marker::PhantomData;
21use tetcore_std::ops::Range;
22use tetcore_std::vec::Vec;
23use tetcore_std::borrow::Borrow;
24use codec::{Encode, Decode, Input, Compact};
25use tetsy_hash_db::Hasher;
26use tetsy_trie_db::{self, node::{NibbleSlicePlan, NodePlan, NodeHandlePlan}, ChildReference,
27	nibble_ops, Partial, NodeCodec as NodeCodecT};
28use crate::error::Error;
29use crate::trie_constants;
30use super::{node_header::{NodeHeader, NodeKind}};
31
32/// Helper struct for trie node decoder. This implements `codec::Input` on a byte slice, while
33/// tracking the absolute position. This is similar to `std::io::Cursor` but does not implement
34/// `Read` and `io` is not in `tetcore-std`.
35struct ByteSliceInput<'a> {
36	data: &'a [u8],
37	offset: usize,
38}
39
40impl<'a> ByteSliceInput<'a> {
41	fn new(data: &'a [u8]) -> Self {
42		ByteSliceInput {
43			data,
44			offset: 0,
45		}
46	}
47
48	fn take(&mut self, count: usize) -> Result<Range<usize>, codec::Error> {
49		if self.offset + count > self.data.len() {
50			return Err("out of data".into());
51		}
52
53		let range = self.offset..(self.offset + count);
54		self.offset += count;
55		Ok(range)
56	}
57}
58
59impl<'a> Input for ByteSliceInput<'a> {
60	fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
61		let remaining = if self.offset <= self.data.len() {
62			Some(self.data.len() - self.offset)
63		} else {
64			None
65		};
66		Ok(remaining)
67	}
68
69	fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> {
70		let range = self.take(into.len())?;
71		into.copy_from_slice(&self.data[range]);
72		Ok(())
73	}
74
75	fn read_byte(&mut self) -> Result<u8, codec::Error> {
76		if self.offset + 1 > self.data.len() {
77			return Err("out of data".into());
78		}
79
80		let byte = self.data[self.offset];
81		self.offset += 1;
82		Ok(byte)
83	}
84}
85
86/// Concrete implementation of a `NodeCodec` with Parity Codec encoding, generic over the `Hasher`
87#[derive(Default, Clone)]
88pub struct NodeCodec<H>(PhantomData<H>);
89
90impl<H: Hasher> NodeCodecT for NodeCodec<H> {
91	type Error = Error;
92	type HashOut = H::Out;
93
94	fn hashed_null_node() -> <H as Hasher>::Out {
95		H::hash(<Self as NodeCodecT>::empty_node())
96	}
97
98	fn decode_plan(data: &[u8]) -> tetcore_std::result::Result<NodePlan, Self::Error> {
99		let mut input = ByteSliceInput::new(data);
100		match NodeHeader::decode(&mut input)? {
101			NodeHeader::Null => Ok(NodePlan::Empty),
102			NodeHeader::Branch(has_value, nibble_count) => {
103				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
104				// check that the padding is valid (if any)
105				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
106					return Err(Error::BadFormat);
107				}
108				let partial = input.take(
109					(nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) / nibble_ops::NIBBLE_PER_BYTE,
110				)?;
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 has_value {
115					let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
116					Some(input.take(count)?)
117				} else {
118					None
119				};
120				let mut children = [
121					None, None, None, None, None, None, None, None,
122					None, None, None, None, None, None, None, None,
123				];
124				for i in 0..nibble_ops::NIBBLE_LENGTH {
125					if bitmap.value_at(i) {
126						let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
127						let range = input.take(count)?;
128						children[i] = Some(if count == H::LENGTH {
129							NodeHandlePlan::Hash(range)
130						} else {
131							NodeHandlePlan::Inline(range)
132						});
133					}
134				}
135				Ok(NodePlan::NibbledBranch {
136					partial: NibbleSlicePlan::new(partial, partial_padding),
137					value,
138					children,
139				})
140			}
141			NodeHeader::Leaf(nibble_count) => {
142				let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0;
143				// check that the padding is valid (if any)
144				if padding && nibble_ops::pad_left(data[input.offset]) != 0 {
145					return Err(Error::BadFormat);
146				}
147				let partial = input.take(
148					(nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) / nibble_ops::NIBBLE_PER_BYTE,
149				)?;
150				let partial_padding = nibble_ops::number_padding(nibble_count);
151				let count = <Compact<u32>>::decode(&mut input)?.0 as usize;
152				Ok(NodePlan::Leaf {
153					partial: NibbleSlicePlan::new(partial, partial_padding),
154					value: input.take(count)?,
155				})
156			}
157		}
158	}
159
160	fn is_empty_node(data: &[u8]) -> bool {
161		data == <Self as NodeCodecT>::empty_node()
162	}
163
164	fn empty_node() -> &'static [u8] {
165		&[trie_constants::EMPTY_TRIE]
166	}
167
168	fn leaf_node(partial: Partial, value: &[u8]) -> Vec<u8> {
169		let mut output = partial_encode(partial, NodeKind::Leaf);
170		value.encode_to(&mut output);
171		output
172	}
173
174	fn extension_node(
175		_partial: impl Iterator<Item = u8>,
176		_nbnibble: usize,
177		_child: ChildReference<<H as Hasher>::Out>,
178	) -> Vec<u8> {
179		unreachable!()
180	}
181
182	fn branch_node(
183		_children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
184		_maybe_value: Option<&[u8]>,
185	) -> Vec<u8> {
186		unreachable!()
187	}
188
189	fn branch_node_nibbled(
190		partial: impl Iterator<Item = u8>,
191		number_nibble: usize,
192		children: impl Iterator<Item = impl Borrow<Option<ChildReference<<H as Hasher>::Out>>>>,
193		maybe_value: Option<&[u8]>,
194	) -> Vec<u8> {
195		let mut output = if maybe_value.is_some() {
196			partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue)
197		} else {
198			partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue)
199		};
200		let bitmap_index = output.len();
201		let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH];
202		(0..BITMAP_LENGTH).for_each(|_|output.push(0));
203		if let Some(value) = maybe_value {
204			value.encode_to(&mut output);
205		};
206		Bitmap::encode(children.map(|maybe_child| match maybe_child.borrow() {
207			Some(ChildReference::Hash(h)) => {
208				h.as_ref().encode_to(&mut output);
209				true
210			}
211			&Some(ChildReference::Inline(inline_data, len)) => {
212				inline_data.as_ref()[..len].encode_to(&mut output);
213				true
214			}
215			None => false,
216		}), bitmap.as_mut());
217		output[bitmap_index..bitmap_index + BITMAP_LENGTH]
218			.copy_from_slice(&bitmap[..BITMAP_LENGTH]);
219		output
220	}
221
222}
223
224// utils
225
226/// Encode and allocate node type header (type and size), and partial value.
227/// It uses an iterator over encoded partial bytes as input.
228fn partial_from_iterator_encode<I: Iterator<Item = u8>>(
229	partial: I,
230	nibble_count: usize,
231	node_kind: NodeKind,
232) -> Vec<u8> {
233	let nibble_count = tetcore_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count);
234
235	let mut output = Vec::with_capacity(3 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE));
236	match node_kind {
237		NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output),
238		NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output),
239		NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output),
240	};
241	output.extend(partial);
242	output
243}
244
245/// Encode and allocate node type header (type and size), and partial value.
246/// Same as `partial_from_iterator_encode` but uses non encoded `Partial` as input.
247fn partial_encode(partial: Partial, node_kind: NodeKind) -> Vec<u8> {
248	let number_nibble_encoded = (partial.0).0 as usize;
249	let nibble_count = partial.1.len() * nibble_ops::NIBBLE_PER_BYTE + number_nibble_encoded;
250
251	let nibble_count = tetcore_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count);
252
253	let mut output = Vec::with_capacity(3 + partial.1.len());
254	match node_kind {
255		NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output),
256		NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output),
257		NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output),
258	};
259	if number_nibble_encoded > 0 {
260		output.push(nibble_ops::pad_right((partial.0).1));
261	}
262	output.extend_from_slice(&partial.1[..]);
263	output
264}
265
266const BITMAP_LENGTH: usize = 2;
267
268/// Radix 16 trie, bitmap encoding implementation,
269/// it contains children mapping information for a branch
270/// (children presence only), it encodes into
271/// a compact bitmap encoding representation.
272pub(crate) struct Bitmap(u16);
273
274impl Bitmap {
275	pub fn decode(data: &[u8]) -> Result<Self, Error> {
276		Ok(Bitmap(u16::decode(&mut &data[..])?))
277	}
278
279	pub fn value_at(&self, i: usize) -> bool {
280		self.0 & (1u16 << i) != 0
281	}
282
283	pub fn encode<I: Iterator<Item = bool>>(has_children: I , dest: &mut [u8]) {
284		let mut bitmap: u16 = 0;
285		let mut cursor: u16 = 1;
286		for v in has_children {
287			if v { bitmap |= cursor }
288			cursor <<= 1;
289		}
290		dest[0] = (bitmap % 256) as u8;
291		dest[1] = (bitmap / 256) as u8;
292	}
293}