Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Handle node decode results in trie
Browse files Browse the repository at this point in the history
  • Loading branch information
ascjones committed Mar 20, 2018
1 parent 8bf433a commit 83aba3e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 41 deletions.
2 changes: 1 addition & 1 deletion util/patricia_trie/src/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl<'a, Q: Query> Lookup<'a, Q> {
// without incrementing the depth.
let mut node_data = &node_data[..];
loop {
match Node::decoded(node_data) {
match Node::decoded(node_data).expect("rlp read from db; qed") {
Node::Leaf(slice, value) => {
return Ok(match slice == key {
true => Some(self.query.decode(value)),
Expand Down
53 changes: 24 additions & 29 deletions util/patricia_trie/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,31 @@ pub enum Node<'a> {

impl<'a> Node<'a> {
/// Decode the `node_rlp` and return the Node.
pub fn decoded(node_rlp: &'a [u8]) -> Self {
pub fn decoded(node_rlp: &'a [u8]) -> Result<Self, DecoderError> {
let r = UntrustedRlp::new(node_rlp);
Node::decode_rlp(&r).expect("Self encoded Rlp should be valid; qed")
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) => Ok(Node::Leaf(slice, r.at(1)?.data()?)),
(slice, false) => Ok(Node::Extension(slice, r.at(1)?.as_raw())),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes = [&[] as &[u8]; 16];
for i in 0..16 {
nodes[i] = r.at(i)?.as_raw();
}
Ok(Node::Branch(nodes, if r.at(16)?.is_empty() { None } else { Some(r.at(16)?.data()?) }))
},
// an empty branch index.
Prototype::Data(0) => Ok(Node::Empty),
// something went wrong.
_ => Err(DecoderError::Custom("Rlp is not valid."))
}
}

/// Encode the node into RLP.
Expand Down Expand Up @@ -90,33 +112,6 @@ impl<'a> Node<'a> {
None
}
}

// TODO: this could implement Decodable? But need to figure out how to unify lifetimes
fn decode_rlp<'b>(r: &UntrustedRlp<'b>) -> Result<Node<'b>, DecoderError> {
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) => Ok(Node::Leaf(slice, r.at(1)?.data()?)),
(slice, false) => Ok(Node::Extension(slice, r.at(1)?.as_raw())),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes = [&[] as &[u8]; 16];
for i in 0..16 {
nodes[i] = r.at(i)?.as_raw();
}
Ok(Node::Branch(nodes, if r.at(16)?.is_empty() { None } else { Some(r.at(16)?.data()?) }))
},
// an empty branch index.
Prototype::Data(0) => Ok(Node::Empty),
// something went wrong.
_ => panic!("Rlp is not valid.")
}
}
}

/// An owning node type. Useful for trie iterators.
Expand Down
38 changes: 28 additions & 10 deletions util/patricia_trie/src/triedb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ impl<'db> TrieDB<'db> {
Node::Extension(ref slice, ref item) => {
write!(f, "'{:?} ", slice)?;
if let Ok(node) = self.get_raw_or_lookup(&*item) {
self.fmt_all(Node::decoded(&node), f, deepness)?;
match Node::decoded(&node) {
Ok(n) => self.fmt_all(n, f, deepness)?,
Err(err) => writeln!(f, "ERROR decoding node extension Rlp: {}", err)?,
}
}
},
Node::Branch(ref nodes, ref value) => {
Expand All @@ -107,12 +110,19 @@ impl<'db> TrieDB<'db> {
}
for i in 0..16 {
let node = self.get_raw_or_lookup(&*nodes[i]);
match node.as_ref().map(|n| Node::decoded(&*n)) {
Ok(Node::Empty) => {},
match node.as_ref() {
Ok(n) => {
self.fmt_indent(f, deepness + 1)?;
write!(f, "'{:x} ", i)?;
self.fmt_all(n, f, deepness + 1)?;
match Node::decoded(&*n) {
Ok(Node::Empty) => {},
Ok(n) => {
self.fmt_indent(f, deepness + 1)?;
write!(f, "'{:x} ", i)?;
self.fmt_all(n, f, deepness + 1)?;
}
Err(e) => {
write!(f, "ERROR decoding node branch Rlp: {}", e)?
}
}
}
Err(e) => {
write!(f, "ERROR: {}", e)?;
Expand All @@ -139,6 +149,11 @@ impl<'db> TrieDB<'db> {
None => Ok(DBValue::from_slice(node))
}
}

/// Create a node from raw rlp bytes, assumes valid rlp because encoded locally
fn decode_node(node: &'db [u8]) -> Node {
Node::decoded(node).expect("rlp read from db; qed")
}
}

impl<'db> Trie for TrieDB<'db> {
Expand All @@ -163,7 +178,10 @@ impl<'db> fmt::Debug for TrieDB<'db> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "c={:?} [", self.hash_count)?;
let root_rlp = self.db.get(self.root).expect("Trie root not found!");
self.fmt_all(Node::decoded(&root_rlp), f, 0)?;
match Node::decoded(&root_rlp) {
Ok(node) => self.fmt_all(node, f, 0)?,
Err(e) => writeln!(f, "ERROR decoding node rlp: {}", e)?,
}
writeln!(f, "]")
}
}
Expand Down Expand Up @@ -218,7 +236,7 @@ impl<'a> TrieDBIterator<'a> {
fn seek<'key>(&mut self, mut node_data: DBValue, mut key: NibbleSlice<'key>) -> super::Result<()> {
loop {
let (data, mid) = {
let node = Node::decoded(&node_data);
let node = TrieDB::decode_node(&node_data);
match node {
Node::Leaf(slice, _) => {
if slice == key {
Expand Down Expand Up @@ -280,7 +298,7 @@ impl<'a> TrieDBIterator<'a> {

/// Descend into a payload.
fn descend(&mut self, d: &[u8]) -> super::Result<()> {
let node = Node::decoded(&self.db.get_raw_or_lookup(d)?).into();
let node = TrieDB::decode_node(&self.db.get_raw_or_lookup(d)?).into();
Ok(self.descend_into_node(node))
}

Expand Down Expand Up @@ -378,7 +396,7 @@ impl<'a> Iterator for TrieDBIterator<'a> {
self.trail.pop();
},
IterStep::Descend(Ok(d)) => {
self.descend_into_node(Node::decoded(&d).into())
self.descend_into_node(TrieDB::decode_node(&d).into())
},
IterStep::Descend(Err(e)) => {
return Some(Err(e))
Expand Down
2 changes: 1 addition & 1 deletion util/patricia_trie/src/triedbmut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl Node {

// decode a node from rlp without getting its children.
fn from_rlp(rlp: &[u8], db: &HashDB, storage: &mut NodeStorage) -> Self {
match RlpNode::decoded(rlp) {
match RlpNode::decoded(rlp).expect("rlp read from db; qed") {
RlpNode::Empty => Node::Empty,
RlpNode::Leaf(k, v) => Node::Leaf(k.encoded(true), DBValue::from_slice(&v)),
RlpNode::Extension(key, cb) => {
Expand Down

0 comments on commit 83aba3e

Please sign in to comment.