// Copyright 2015-2019 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 rstd::marker::PhantomData;
use rstd::vec::Vec;
use codec::{Encode, Decode, Compact};
use hash_db::Hasher;
use trie_db::{self, DBValue, NibbleSlice, node::Node, ChildReference};
use crate::error::Error;
use super::{EMPTY_TRIE, LEAF_NODE_OFFSET, LEAF_NODE_BIG, EXTENSION_NODE_OFFSET,
EXTENSION_NODE_BIG, take, partial_to_key, node_header::NodeHeader, branch_node};
/// Concrete implementation of a `NodeCodec` with Parity Codec encoding, generic over the `Hasher`
#[derive(Default, Clone)]
pub struct NodeCodec(PhantomData);
impl trie_db::NodeCodec for NodeCodec {
type Error = Error;
fn hashed_null_node() -> H::Out {
H::hash(&[0u8][..])
}
fn decode(data: &[u8]) -> ::rstd::result::Result {
use Error::BadFormat;
let input = &mut &*data;
match NodeHeader::decode(input).ok_or(BadFormat)? {
NodeHeader::Null => Ok(Node::Empty),
NodeHeader::Branch(has_value) => {
let bitmap = u16::decode(input).ok_or(BadFormat)?;
let value = if has_value {
let count = >::decode(input).ok_or(BadFormat)?.0 as usize;
Some(take(input, count).ok_or(BadFormat)?)
} else {
None
};
let mut children = [None; 16];
let mut pot_cursor = 1;
for i in 0..16 {
if bitmap & pot_cursor != 0 {
let count = >::decode(input).ok_or(BadFormat)?.0 as usize;
children[i] = Some(take(input, count).ok_or(BadFormat)?);
}
pot_cursor <<= 1;
}
Ok(Node::Branch(children, value))
}
NodeHeader::Extension(nibble_count) => {
if nibble_count % 2 == 1 && input[0] & 0xf0 != 0x00 {
return Err(BadFormat);
}
let nibble_data = take(input, (nibble_count + 1) / 2).ok_or(BadFormat)?;
let nibble_slice = NibbleSlice::new_offset(nibble_data, nibble_count % 2);
let count = >::decode(input).ok_or(BadFormat)?.0 as usize;
Ok(Node::Extension(nibble_slice, take(input, count).ok_or(BadFormat)?))
}
NodeHeader::Leaf(nibble_count) => {
if nibble_count % 2 == 1 && input[0] & 0xf0 != 0x00 {
return Err(BadFormat);
}
let nibble_data = take(input, (nibble_count + 1) / 2).ok_or(BadFormat)?;
let nibble_slice = NibbleSlice::new_offset(nibble_data, nibble_count % 2);
let count = >::decode(input).ok_or(BadFormat)?.0 as usize;
Ok(Node::Leaf(nibble_slice, take(input, count).ok_or(BadFormat)?))
}
}
}
fn try_decode_hash(data: &[u8]) -> Option {
if data.len() == H::LENGTH {
let mut r = H::Out::default();
r.as_mut().copy_from_slice(data);
Some(r)
} else {
None
}
}
fn is_empty_node(data: &[u8]) -> bool {
data == &[EMPTY_TRIE][..]
}
fn empty_node() -> Vec {
[EMPTY_TRIE].to_vec()
}
// FIXME: refactor this so that `partial` isn't already encoded with HPE. Should just be an `impl Iterator- `.
fn leaf_node(partial: &[u8], value: &[u8]) -> Vec {
let mut output = partial_to_key(partial, LEAF_NODE_OFFSET, LEAF_NODE_BIG);
value.encode_to(&mut output);
output
}
// FIXME: refactor this so that `partial` isn't already encoded with HPE. Should just be an `impl Iterator
- `.
fn ext_node(partial: &[u8], child: ChildReference) -> Vec {
let mut output = partial_to_key(partial, EXTENSION_NODE_OFFSET, EXTENSION_NODE_BIG);
match child {
ChildReference::Hash(h) =>
h.as_ref().encode_to(&mut output),
ChildReference::Inline(inline_data, len) =>
(&AsRef::<[u8]>::as_ref(&inline_data)[..len]).encode_to(&mut output),
};
output
}
fn branch_node(children: I, maybe_value: Option) -> Vec
where I: IntoIterator
- >> + Iterator
- >>
{
let mut output = [0, 0, 0].to_vec();
let have_value = if let Some(value) = maybe_value {
(&*value).encode_to(&mut output);
true
} else {
false
};
let prefix = branch_node(have_value, children.map(|maybe_child| match maybe_child {
Some(ChildReference::Hash(h)) => {
h.as_ref().encode_to(&mut output);
true
}
Some(ChildReference::Inline(inline_data, len)) => {
(&AsRef::<[u8]>::as_ref(&inline_data)[..len]).encode_to(&mut output);
true
}
None => false,
}));
output[0..3].copy_from_slice(&prefix[..]);
output
}
}