// Copyright 2015-2020 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see . //! `NodeCodec` implementation for Substrate's trie format. use sp_std::marker::PhantomData; use sp_std::ops::Range; use sp_std::vec::Vec; use sp_std::borrow::Borrow; use codec::{Encode, Decode, Input, Compact}; use hash_db::Hasher; use trie_db::{self, node::{NibbleSlicePlan, NodePlan, NodeHandlePlan}, ChildReference, nibble_ops, Partial, NodeCodec as NodeCodecT}; use crate::error::Error; use crate::trie_constants; use super::{node_header::{NodeHeader, NodeKind}}; /// Helper struct for trie node decoder. This implements `codec::Input` on a byte slice, while /// tracking the absolute position. This is similar to `std::io::Cursor` but does not implement /// `Read` and `io` is not in `sp-std`. struct ByteSliceInput<'a> { data: &'a [u8], offset: usize, } impl<'a> ByteSliceInput<'a> { fn new(data: &'a [u8]) -> Self { ByteSliceInput { data, offset: 0, } } fn take(&mut self, count: usize) -> Result, codec::Error> { if self.offset + count > self.data.len() { return Err("out of data".into()); } let range = self.offset..(self.offset + count); self.offset += count; Ok(range) } } impl<'a> Input for ByteSliceInput<'a> { fn remaining_len(&mut self) -> Result, codec::Error> { let remaining = if self.offset <= self.data.len() { Some(self.data.len() - self.offset) } else { None }; Ok(remaining) } fn read(&mut self, into: &mut [u8]) -> Result<(), codec::Error> { let range = self.take(into.len())?; into.copy_from_slice(&self.data[range]); Ok(()) } fn read_byte(&mut self) -> Result { if self.offset + 1 > self.data.len() { return Err("out of data".into()); } let byte = self.data[self.offset]; self.offset += 1; Ok(byte) } } /// Concrete implementation of a `NodeCodec` with Parity Codec encoding, generic over the `Hasher` #[derive(Default, Clone)] pub struct NodeCodec(PhantomData); impl NodeCodecT for NodeCodec { type Error = Error; type HashOut = H::Out; fn hashed_null_node() -> ::Out { H::hash(::empty_node()) } fn decode_plan(data: &[u8]) -> sp_std::result::Result { let mut input = ByteSliceInput::new(data); match NodeHeader::decode(&mut input)? { NodeHeader::Null => Ok(NodePlan::Empty), NodeHeader::Branch(has_value, nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { return Err(Error::BadFormat); } let partial = input.take( (nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) / nibble_ops::NIBBLE_PER_BYTE, )?; let partial_padding = nibble_ops::number_padding(nibble_count); let bitmap_range = input.take(BITMAP_LENGTH)?; let bitmap = Bitmap::decode(&data[bitmap_range])?; let value = if has_value { let count = >::decode(&mut input)?.0 as usize; Some(input.take(count)?) } else { None }; let mut children = [ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ]; for i in 0..nibble_ops::NIBBLE_LENGTH { if bitmap.value_at(i) { let count = >::decode(&mut input)?.0 as usize; let range = input.take(count)?; children[i] = Some(if count == H::LENGTH { NodeHandlePlan::Hash(range) } else { NodeHandlePlan::Inline(range) }); } } Ok(NodePlan::NibbledBranch { partial: NibbleSlicePlan::new(partial, partial_padding), value, children, }) } NodeHeader::Leaf(nibble_count) => { let padding = nibble_count % nibble_ops::NIBBLE_PER_BYTE != 0; // check that the padding is valid (if any) if padding && nibble_ops::pad_left(data[input.offset]) != 0 { return Err(Error::BadFormat); } let partial = input.take( (nibble_count + (nibble_ops::NIBBLE_PER_BYTE - 1)) / nibble_ops::NIBBLE_PER_BYTE, )?; let partial_padding = nibble_ops::number_padding(nibble_count); let count = >::decode(&mut input)?.0 as usize; Ok(NodePlan::Leaf { partial: NibbleSlicePlan::new(partial, partial_padding), value: input.take(count)?, }) } } } fn is_empty_node(data: &[u8]) -> bool { data == ::empty_node() } fn empty_node() -> &'static [u8] { &[trie_constants::EMPTY_TRIE] } fn leaf_node(partial: Partial, value: &[u8]) -> Vec { let mut output = partial_encode(partial, NodeKind::Leaf); value.encode_to(&mut output); output } fn extension_node( _partial: impl Iterator, _nbnibble: usize, _child: ChildReference<::Out>, ) -> Vec { unreachable!() } fn branch_node( _children: impl Iterator::Out>>>>, _maybe_value: Option<&[u8]>, ) -> Vec { unreachable!() } fn branch_node_nibbled( partial: impl Iterator, number_nibble: usize, children: impl Iterator::Out>>>>, maybe_value: Option<&[u8]>, ) -> Vec { let mut output = if maybe_value.is_some() { partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchWithValue) } else { partial_from_iterator_encode(partial, number_nibble, NodeKind::BranchNoValue) }; let bitmap_index = output.len(); let mut bitmap: [u8; BITMAP_LENGTH] = [0; BITMAP_LENGTH]; (0..BITMAP_LENGTH).for_each(|_|output.push(0)); if let Some(value) = maybe_value { value.encode_to(&mut output); }; Bitmap::encode(children.map(|maybe_child| match maybe_child.borrow() { Some(ChildReference::Hash(h)) => { h.as_ref().encode_to(&mut output); true } &Some(ChildReference::Inline(inline_data, len)) => { inline_data.as_ref()[..len].encode_to(&mut output); true } None => false, }), bitmap.as_mut()); output[bitmap_index..bitmap_index + BITMAP_LENGTH] .copy_from_slice(&bitmap[..BITMAP_LENGTH]); output } } // utils /// Encode and allocate node type header (type and size), and partial value. /// It uses an iterator over encoded partial bytes as input. fn partial_from_iterator_encode>( partial: I, nibble_count: usize, node_kind: NodeKind, ) -> Vec { let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); let mut output = Vec::with_capacity(3 + (nibble_count / nibble_ops::NIBBLE_PER_BYTE)); match node_kind { NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output), NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output), }; output.extend(partial); output } /// Encode and allocate node type header (type and size), and partial value. /// Same as `partial_from_iterator_encode` but uses non encoded `Partial` as input. fn partial_encode(partial: Partial, node_kind: NodeKind) -> Vec { let number_nibble_encoded = (partial.0).0 as usize; let nibble_count = partial.1.len() * nibble_ops::NIBBLE_PER_BYTE + number_nibble_encoded; let nibble_count = sp_std::cmp::min(trie_constants::NIBBLE_SIZE_BOUND, nibble_count); let mut output = Vec::with_capacity(3 + partial.1.len()); match node_kind { NodeKind::Leaf => NodeHeader::Leaf(nibble_count).encode_to(&mut output), NodeKind::BranchWithValue => NodeHeader::Branch(true, nibble_count).encode_to(&mut output), NodeKind::BranchNoValue => NodeHeader::Branch(false, nibble_count).encode_to(&mut output), }; if number_nibble_encoded > 0 { output.push(nibble_ops::pad_right((partial.0).1)); } output.extend_from_slice(&partial.1[..]); output } const BITMAP_LENGTH: usize = 2; /// Radix 16 trie, bitmap encoding implementation, /// it contains children mapping information for a branch /// (children presence only), it encodes into /// a compact bitmap encoding representation. pub(crate) struct Bitmap(u16); impl Bitmap { pub fn decode(data: &[u8]) -> Result { Ok(Bitmap(u16::decode(&mut &data[..])?)) } pub fn value_at(&self, i: usize) -> bool { self.0 & (1u16 << i) != 0 } pub fn encode>(has_children: I , dest: &mut [u8]) { let mut bitmap: u16 = 0; let mut cursor: u16 = 1; for v in has_children { if v { bitmap |= cursor } cursor <<= 1; } dest[0] = (bitmap % 256) as u8; dest[1] = (bitmap / 256) as u8; } }