// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// 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 .
use elastic_array::ElasticArray36;
use nibbleslice::*;
use bytes::*;
use rlp::*;
use super::journal::*;
use hashdb::DBValue;
/// Partial node key type.
pub type NodeKey = ElasticArray36;
/// Type of node in the trie and essential information thereof.
#[derive(Eq, PartialEq, Debug)]
pub enum Node {
/// Null trie node; could be an empty root or an empty branch entry.
Empty,
/// Leaf node; has key slice and value. Value may not be empty.
Leaf(NodeKey, DBValue),
/// Extension node; has key slice and node data. Data may not be null.
Extension(NodeKey, DBValue),
/// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data.
Branch([NodeKey; 16], Option)
}
impl Clone for Node {
fn clone(&self) -> Node {
match *self {
Node::Empty => Node::Empty,
Node::Leaf(ref k, ref v) => Node::Leaf(k.clone(), v.clone()),
Node::Extension(ref k, ref v) => Node::Extension(k.clone(), v.clone()),
Node::Branch(ref k, ref v) => {
let mut branch = [NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(),
NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(),
NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new()];
for i in 0 .. 16 {
branch[i] = k[i].clone();
}
Node::Branch(branch, v.clone())
}
}
}
}
impl Node {
/// Decode the `node_rlp` and return the Node.
pub fn decoded(node_rlp: &[u8]) -> Node {
let r = Rlp::new(node_rlp);
match r.prototype() {
// either leaf or extension - decode first item with NibbleSlice::???
// and use is_leaf return to figure out which.
// if leaf, second item is a value (is_data())
// if extension, second item is a node (either SHA3 to be looked up and
// fed back into this function or inline RLP which can be fed back into this function).
Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0).data()) {
(slice, true) => Node::Leaf(slice.encoded(true), DBValue::from_slice(r.at(1).data())),
(slice, false) => Node::Extension(slice.encoded(false), DBValue::from_slice(r.at(1).as_raw())),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes: [NodeKey; 16] = [NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(),
NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(),
NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new(), NodeKey::new()];
for i in 0..16 {
nodes[i] = NodeKey::from_slice(r.at(i).as_raw());
}
Node::Branch(nodes, if r.at(16).is_empty() { None } else { Some(DBValue::from_slice(r.at(16).data())) })
},
// an empty branch index.
Prototype::Data(0) => Node::Empty,
// something went wrong.
_ => panic!("Rlp is not valid.")
}
}
/// Encode the node into RLP.
///
/// Will always return the direct node RLP even if it's 32 or more bytes. To get the
/// RLP which would be valid for using in another node, use `encoded_and_added()`.
pub fn encoded(&self) -> Bytes {
match *self {
Node::Leaf(ref slice, ref value) => {
let mut stream = RlpStream::new_list(2);
stream.append(&&**slice);
stream.append(&&**value);
stream.out()
},
Node::Extension(ref slice, ref raw_rlp) => {
let mut stream = RlpStream::new_list(2);
stream.append(&&**slice);
stream.append_raw(&&*raw_rlp, 1);
stream.out()
},
Node::Branch(ref nodes, ref value) => {
let mut stream = RlpStream::new_list(17);
for i in 0..16 {
stream.append_raw(&*nodes[i], 1);
}
match *value {
Some(ref n) => { stream.append(&&**n); },
None => { stream.append_empty_data(); },
}
stream.out()
},
Node::Empty => {
let mut stream = RlpStream::new();
stream.append_empty_data();
stream.out()
}
}
}
/// Encode the node, adding it to `journal` if necessary and return the RLP valid for
/// insertion into a parent node.
pub fn encoded_and_added(&self, journal: &mut Journal) -> DBValue {
let mut stream = RlpStream::new();
match *self {
Node::Leaf(ref slice, ref value) => {
stream.begin_list(2);
stream.append(&&**slice);
stream.append(&&**value);
},
Node::Extension(ref slice, ref raw_rlp) => {
stream.begin_list(2);
stream.append(&&**slice);
stream.append_raw(&&**raw_rlp, 1);
},
Node::Branch(ref nodes, ref value) => {
stream.begin_list(17);
for i in 0..16 {
stream.append_raw(&*nodes[i], 1);
}
match *value {
Some(ref n) => { stream.append(&&**n); },
None => { stream.append_empty_data(); },
}
},
Node::Empty => {
stream.append_empty_data();
}
}
let node = DBValue::from_slice(stream.as_raw());
match node.len() {
0 ... 31 => node,
_ => {
let mut stream = RlpStream::new();
journal.new_node(node, &mut stream);
DBValue::from_slice(stream.as_raw())
}
}
}
}