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

Commit

Permalink
Decode Node with new Rlp Result API
Browse files Browse the repository at this point in the history
  • Loading branch information
ascjones committed Mar 12, 2018
1 parent f17d781 commit efb993b
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 41 deletions.
6 changes: 2 additions & 4 deletions util/patricia_trie/src/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

use hashdb::HashDB;
use nibbleslice::NibbleSlice;
use rlp::Rlp;
use ethereum_types::H256;

use super::{TrieError, Query};
Expand Down Expand Up @@ -82,9 +81,8 @@ impl<'a, Q: Query> Lookup<'a, Q> {
}

// check if new node data is inline or hash.
let r = Rlp::new(node_data);
if r.is_data() && r.size() == 32 {
hash = r.as_val();
if let Some(h) = Node::try_decode_hash(&node_data) {
hash = h;
break
}
}
Expand Down
61 changes: 38 additions & 23 deletions util/patricia_trie/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use ethereum_types::H256;
use elastic_array::ElasticArray36;
use nibbleslice::NibbleSlice;
use nibblevec::NibbleVec;
Expand Down Expand Up @@ -41,29 +42,7 @@ impl<'a> Node<'a> {
/// Decode the `node_rlp` and return the Node.
pub fn decoded(node_rlp: &'a [u8]) -> Self {
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, r.at(1).data()),
(slice, false) => 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();
}
Node::Branch(nodes, if r.at(16).is_empty() { None } else { Some(r.at(16).data()) })
},
// an empty branch index.
Prototype::Data(0) => Node::Empty,
// something went wrong.
_ => panic!("Rlp is not valid.")
}
Node::decode_rlp(&r).expect("Self encoded Rlp should be valid; qed")
}

/// Encode the node into RLP.
Expand Down Expand Up @@ -102,6 +81,42 @@ impl<'a> Node<'a> {
}
}
}

pub fn try_decode_hash(node_data: &[u8]) -> Option<H256> {
let r = Rlp::new(node_data);
if r.is_data() && r.size() == 32 {
Some(r.as_val().expect("Hash is the correct size of 32 bytes; qed"))
} else {
None
}
}

// TODO: this could implement Decodable? But need to figure out how to unify lifetimes
fn decode_rlp<'b>(r: &Rlp<'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
10 changes: 3 additions & 7 deletions util/patricia_trie/src/triedb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use std::fmt;
use hashdb::*;
use nibbleslice::NibbleSlice;
use rlp::*;
use super::node::{Node, OwnedNode};
use super::lookup::Lookup;
use super::{Trie, TrieItem, TrieError, TrieIterator, Query};
Expand Down Expand Up @@ -133,14 +132,11 @@ impl<'db> TrieDB<'db> {
/// This could be a simple identity operation in the case that the node is sufficiently small, but
/// may require a database lookup.
fn get_raw_or_lookup(&'db self, node: &'db [u8]) -> super::Result<DBValue> {
// check if its keccak + len
let r = Rlp::new(node);
match r.is_data() && r.size() == 32 {
true => {
let key = r.as_val::<H256>();
match Node::try_decode_hash(node) {
Some(key) => {
self.db.get(&key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key)))
}
false => Ok(DBValue::from_slice(node))
None => Ok(DBValue::from_slice(node))
}
}
}
Expand Down
13 changes: 6 additions & 7 deletions util/patricia_trie/src/triedbmut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@ enum Node {
impl Node {
// load an inline node into memory or get the hash to do the lookup later.
fn inline_or_hash(node: &[u8], db: &HashDB, storage: &mut NodeStorage) -> NodeHandle {
let r = Rlp::new(node);
if r.is_data() && r.size() == 32 {
NodeHandle::Hash(r.as_val::<H256>())
} else {
let child = Node::from_rlp(node, db, storage);
NodeHandle::InMemory(storage.alloc(Stored::New(child)))
}
RlpNode::try_decode_hash(&node)
.map(NodeHandle::Hash)
.unwrap_or_else(|| {
let child = Node::from_rlp(node, db, storage);
NodeHandle::InMemory(storage.alloc(Stored::New(child)))
})
}

// decode a node from rlp without getting its children.
Expand Down

0 comments on commit efb993b

Please sign in to comment.