use crate::{
nibble_ops::NIBBLE_LENGTH,
node::{Node, NodeHandle, NodeHandlePlan, NodePlan, OwnedNode, ValuePlan},
rstd::{boxed::Box, convert::TryInto, marker::PhantomData, result, sync::Arc, vec, vec::Vec},
CError, ChildReference, DBValue, NibbleVec, NodeCodec, Result, TrieDB, TrieDBRawIterator,
TrieError, TrieHash, TrieLayout,
};
use hash_db::{HashDB, Prefix};
const OMIT_VALUE_HASH: crate::node::Value<'static> = crate::node::Value::Inline(&[]);
struct EncoderStackEntry<C: NodeCodec> {
prefix: NibbleVec,
node: Arc<OwnedNode<DBValue>>,
child_index: usize,
omit_children: Vec<bool>,
omit_value: bool,
output_index: usize,
_marker: PhantomData<C>,
}
impl<C: NodeCodec> EncoderStackEntry<C> {
fn advance_child_index(
&mut self,
child_prefix: &NibbleVec,
) -> result::Result<(), &'static str> {
match self.node.node_plan() {
NodePlan::Empty | NodePlan::Leaf { .. } =>
return Err("empty and leaf nodes have no children"),
NodePlan::Extension { .. } =>
if self.child_index != 0 {
return Err("extension node cannot have multiple children")
},
NodePlan::Branch { .. } => {
if child_prefix.len() <= self.prefix.len() {
return Err("child_prefix does not contain prefix")
}
let child_index = child_prefix.at(self.prefix.len()) as usize;
if child_index < self.child_index {
return Err("iterator returned children in non-ascending order by prefix")
}
self.child_index = child_index;
},
NodePlan::NibbledBranch { partial, .. } => {
if child_prefix.len() <= self.prefix.len() + partial.len() {
return Err("child_prefix does not contain prefix and node partial")
}
let child_index = child_prefix.at(self.prefix.len() + partial.len()) as usize;
if child_index < self.child_index {
return Err("iterator returned children in non-ascending order by prefix")
}
self.child_index = child_index;
},
}
Ok(())
}
fn encode_node(&mut self) -> Result<Vec<u8>, C::HashOut, C::Error> {
let node_data = self.node.data();
let node_plan = self.node.node_plan();
let mut encoded = match node_plan {
NodePlan::Empty => node_data.to_vec(),
NodePlan::Leaf { partial, value: _ } =>
if self.omit_value {
let partial = partial.build(node_data);
C::leaf_node(partial.right_iter(), partial.len(), OMIT_VALUE_HASH)
} else {
node_data.to_vec()
},
NodePlan::Extension { partial, child: _ } =>
if !self.omit_children[0] {
node_data.to_vec()
} else {
let partial = partial.build(node_data);
let empty_child = ChildReference::Inline(C::HashOut::default(), 0);
C::extension_node(partial.right_iter(), partial.len(), empty_child)
},
NodePlan::Branch { value, children } => {
let value = if self.omit_value {
value.is_some().then_some(OMIT_VALUE_HASH)
} else {
value.as_ref().map(|v| v.build(node_data))
};
C::branch_node(
Self::branch_children(node_data, &children, &self.omit_children)?.iter(),
value,
)
},
NodePlan::NibbledBranch { partial, value, children } => {
let partial = partial.build(node_data);
let value = if self.omit_value {
value.is_some().then_some(OMIT_VALUE_HASH)
} else {
value.as_ref().map(|v| v.build(node_data))
};
C::branch_node_nibbled(
partial.right_iter(),
partial.len(),
Self::branch_children(node_data, &children, &self.omit_children)?.iter(),
value,
)
},
};
if self.omit_value {
if let Some(header) = C::ESCAPE_HEADER {
encoded.insert(0, header);
} else {
return Err(Box::new(TrieError::InvalidStateRoot(Default::default())))
}
}
Ok(encoded)
}
fn branch_children(
node_data: &[u8],
child_handles: &[Option<NodeHandlePlan>; NIBBLE_LENGTH],
omit_children: &[bool],
) -> Result<[Option<ChildReference<C::HashOut>>; NIBBLE_LENGTH], C::HashOut, C::Error> {
let empty_child = ChildReference::Inline(C::HashOut::default(), 0);
let mut children = [None; NIBBLE_LENGTH];
for i in 0..NIBBLE_LENGTH {
children[i] = if omit_children[i] {
Some(empty_child)
} else if let Some(child_plan) = &child_handles[i] {
let child_ref = child_plan.build(node_data).try_into().map_err(|hash| {
Box::new(TrieError::InvalidHash(C::HashOut::default(), hash))
})?;
Some(child_ref)
} else {
None
};
}
Ok(children)
}
}
fn detached_value<L: TrieLayout>(
db: &TrieDB<L>,
value: &ValuePlan,
node_data: &[u8],
node_prefix: Prefix,
) -> Option<Vec<u8>> {
let fetched;
match value {
ValuePlan::Node(hash_plan) => {
if let Ok(value) =
TrieDBRawIterator::fetch_value(db, &node_data[hash_plan.clone()], node_prefix)
{
fetched = value;
} else {
return None
}
},
_ => return None,
}
Some(fetched)
}
pub fn encode_compact<L>(db: &TrieDB<L>) -> Result<Vec<Vec<u8>>, TrieHash<L>, CError<L>>
where
L: TrieLayout,
{
let mut output = Vec::new();
let mut stack: Vec<EncoderStackEntry<L::Codec>> = Vec::new();
let mut iter = TrieDBRawIterator::new(db)?;
while let Some(item) = iter.next_raw_item(db) {
match item {
Ok((prefix, node_hash, node)) => {
if node_hash.is_none() {
continue
}
while let Some(mut last_entry) = stack.pop() {
if prefix.starts_with(&last_entry.prefix) {
last_entry.advance_child_index(&prefix).expect(
"all errors from advance_child_index indicate bugs with \
TrieDBRawIterator or this function",
);
last_entry.omit_children[last_entry.child_index] = true;
last_entry.child_index += 1;
stack.push(last_entry);
break
} else {
output[last_entry.output_index] = last_entry.encode_node()?;
}
}
let (children_len, detached_value) = match node.node_plan() {
NodePlan::Empty => (0, None),
NodePlan::Leaf { value, .. } =>
(0, detached_value(db, value, node.data(), prefix.as_prefix())),
NodePlan::Extension { .. } => (1, None),
NodePlan::NibbledBranch { value: Some(value), .. } |
NodePlan::Branch { value: Some(value), .. } =>
(NIBBLE_LENGTH, detached_value(db, value, node.data(), prefix.as_prefix())),
NodePlan::NibbledBranch { value: None, .. } |
NodePlan::Branch { value: None, .. } => (NIBBLE_LENGTH, None),
};
stack.push(EncoderStackEntry {
prefix: prefix.clone(),
node: node.clone(),
child_index: 0,
omit_children: vec![false; children_len],
omit_value: detached_value.is_some(),
output_index: output.len(),
_marker: PhantomData::default(),
});
output.push(Vec::new());
if let Some(value) = detached_value {
output.push(value);
}
},
Err(err) => match *err {
TrieError::IncompleteDatabase(_) => {},
_ => return Err(err),
},
}
}
while let Some(mut entry) = stack.pop() {
output[entry.output_index] = entry.encode_node()?;
}
Ok(output)
}
struct DecoderStackEntry<'a, C: NodeCodec> {
node: Node<'a>,
child_index: usize,
children: Vec<Option<ChildReference<C::HashOut>>>,
attached_value: Option<&'a [u8]>,
_marker: PhantomData<C>,
}
impl<'a, C: NodeCodec> DecoderStackEntry<'a, C> {
fn advance_child_index(&mut self) -> Result<bool, C::HashOut, C::Error> {
match self.node {
Node::Extension(_, child) if self.child_index == 0 => {
match child {
NodeHandle::Inline(data) if data.is_empty() => return Ok(false),
_ => {
let child_ref = child.try_into().map_err(|hash| {
Box::new(TrieError::InvalidHash(C::HashOut::default(), hash))
})?;
self.children[self.child_index] = Some(child_ref);
},
}
self.child_index += 1;
},
Node::Branch(children, _) | Node::NibbledBranch(_, children, _) => {
while self.child_index < NIBBLE_LENGTH {
match children[self.child_index] {
Some(NodeHandle::Inline(data)) if data.is_empty() => return Ok(false),
Some(child) => {
let child_ref = child.try_into().map_err(|hash| {
Box::new(TrieError::InvalidHash(C::HashOut::default(), hash))
})?;
self.children[self.child_index] = Some(child_ref);
},
None => {},
}
self.child_index += 1;
}
},
_ => {},
}
Ok(true)
}
fn push_to_prefix(&self, prefix: &mut NibbleVec) {
match self.node {
Node::Empty => {},
Node::Leaf(partial, _) | Node::Extension(partial, _) => {
prefix.append_partial(partial.right());
},
Node::Branch(_, _) => {
prefix.push(self.child_index as u8);
},
Node::NibbledBranch(partial, _, _) => {
prefix.append_partial(partial.right());
prefix.push(self.child_index as u8);
},
}
}
fn pop_from_prefix(&self, prefix: &mut NibbleVec) {
match self.node {
Node::Empty => {},
Node::Leaf(partial, _) | Node::Extension(partial, _) => {
prefix.drop_lasts(partial.len());
},
Node::Branch(_, _) => {
prefix.pop();
},
Node::NibbledBranch(partial, _, _) => {
prefix.pop();
prefix.drop_lasts(partial.len());
},
}
}
fn encode_node(self, attached_hash: Option<&[u8]>) -> Vec<u8> {
let attached_hash = attached_hash.map(|h| crate::node::Value::Node(h));
match self.node {
Node::Empty => C::empty_node().to_vec(),
Node::Leaf(partial, value) =>
C::leaf_node(partial.right_iter(), partial.len(), attached_hash.unwrap_or(value)),
Node::Extension(partial, _) => C::extension_node(
partial.right_iter(),
partial.len(),
self.children[0].expect("required by method precondition; qed"),
),
Node::Branch(_, value) => C::branch_node(
self.children.into_iter(),
if attached_hash.is_some() { attached_hash } else { value },
),
Node::NibbledBranch(partial, _, value) => C::branch_node_nibbled(
partial.right_iter(),
partial.len(),
self.children.iter(),
if attached_hash.is_some() { attached_hash } else { value },
),
}
}
}
pub fn decode_compact<L, DB>(
db: &mut DB,
encoded: &[Vec<u8>],
) -> Result<(TrieHash<L>, usize), TrieHash<L>, CError<L>>
where
L: TrieLayout,
DB: HashDB<L::Hash, DBValue>,
{
decode_compact_from_iter::<L, DB, _>(db, encoded.iter().map(Vec::as_slice))
}
pub fn decode_compact_from_iter<'a, L, DB, I>(
db: &mut DB,
encoded: I,
) -> Result<(TrieHash<L>, usize), TrieHash<L>, CError<L>>
where
L: TrieLayout,
DB: HashDB<L::Hash, DBValue>,
I: IntoIterator<Item = &'a [u8]>,
{
let mut stack: Vec<DecoderStackEntry<L::Codec>> = Vec::new();
let mut prefix = NibbleVec::new();
let mut iter = encoded.into_iter().enumerate();
while let Some((i, encoded_node)) = iter.next() {
let mut attached_node = 0;
if let Some(header) = L::Codec::ESCAPE_HEADER {
if encoded_node.starts_with(&[header]) {
attached_node = 1;
}
}
let node = L::Codec::decode(&encoded_node[attached_node..])
.map_err(|err| Box::new(TrieError::DecoderError(<TrieHash<L>>::default(), err)))?;
let children_len = match node {
Node::Empty | Node::Leaf(..) => 0,
Node::Extension(..) => 1,
Node::Branch(..) | Node::NibbledBranch(..) => NIBBLE_LENGTH,
};
let mut last_entry = DecoderStackEntry {
node,
child_index: 0,
children: vec![None; children_len],
attached_value: None,
_marker: PhantomData::default(),
};
if attached_node > 0 {
if let Some((_, fetched_value)) = iter.next() {
last_entry.attached_value = Some(fetched_value);
} else {
return Err(Box::new(TrieError::IncompleteDatabase(<TrieHash<L>>::default())))
}
}
loop {
if !last_entry.advance_child_index()? {
last_entry.push_to_prefix(&mut prefix);
stack.push(last_entry);
break
}
let hash = last_entry
.attached_value
.as_ref()
.map(|value| db.insert(prefix.as_prefix(), value));
let node_data = last_entry.encode_node(hash.as_ref().map(|h| h.as_ref()));
let node_hash = db.insert(prefix.as_prefix(), node_data.as_ref());
if let Some(entry) = stack.pop() {
last_entry = entry;
last_entry.pop_from_prefix(&mut prefix);
last_entry.children[last_entry.child_index] = Some(ChildReference::Hash(node_hash));
last_entry.child_index += 1;
} else {
return Ok((node_hash, i + 1))
}
}
}
Err(Box::new(TrieError::IncompleteDatabase(<TrieHash<L>>::default())))
}