diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index dc211c3541d..88d2bc66e02 100644 --- a/util/patricia_trie/src/lookup.rs +++ b/util/patricia_trie/src/lookup.rs @@ -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)), diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs index 703bc3f34bf..47807940fee 100644 --- a/util/patricia_trie/src/node.rs +++ b/util/patricia_trie/src/node.rs @@ -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 { 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. @@ -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, 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. diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index cd31a48f123..682f12467d3 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -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) => { @@ -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)?; @@ -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> { @@ -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, "]") } } @@ -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 { @@ -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)) } @@ -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)) diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs index 51520239b40..98215de012f 100644 --- a/util/patricia_trie/src/triedbmut.rs +++ b/util/patricia_trie/src/triedbmut.rs @@ -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) => {