This commit is contained in:
debris 2015-12-01 18:26:07 +01:00
commit 8a2082d217
3 changed files with 127 additions and 18 deletions

View File

@ -40,6 +40,38 @@ use std::error::Error as StdError;
use uint::{U128, U256}; use uint::{U128, U256};
use hash::FixedHash; use hash::FixedHash;
pub struct PrettySlice<'a> (&'a [u8]);
impl<'a> fmt::Debug for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
try!(write!(f, "{:02x}", self.0[i]));
}
Ok(())
}
}
pub trait ToPretty {
fn pretty(&self) -> PrettySlice;
}
impl<'a> ToPretty for &'a [u8] {
fn pretty(&self) -> PrettySlice {
PrettySlice(self)
}
}
impl<'a> ToPretty for &'a Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.bytes())
}
}
impl ToPretty for Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.bytes())
}
}
/// Vector of bytes /// Vector of bytes
pub type Bytes = Vec<u8>; pub type Bytes = Vec<u8>;

View File

@ -1,5 +1,6 @@
//! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. //! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
use std::cmp::*; use std::cmp::*;
use std::fmt;
use bytes::*; use bytes::*;
/// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. /// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets.
@ -25,7 +26,7 @@ use bytes::*;
/// assert_eq!(n2.mid(3).common_prefix(&n1), 3); /// assert_eq!(n2.mid(3).common_prefix(&n1), 3);
/// } /// }
/// ``` /// ```
#[derive(Debug, Copy, Clone, Eq, Ord)] #[derive(Copy, Clone, Eq, Ord)]
pub struct NibbleSlice<'a> { pub struct NibbleSlice<'a> {
data: &'a [u8], data: &'a [u8],
offset: usize, offset: usize,
@ -122,6 +123,15 @@ impl<'a> PartialOrd for NibbleSlice<'a> {
} }
} }
impl<'a> fmt::Debug for NibbleSlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.len() {
try!(write!(f, "{:01x}", self.at(i)));
}
Ok(())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::NibbleSlice; use super::NibbleSlice;

View File

@ -116,7 +116,7 @@ impl Diff {
self.0.push(Operation::New(rlp_sha3, rlp)); self.0.push(Operation::New(rlp_sha3, rlp));
} }
else { else {
trace!("new_node: inline node {:?}", &rlp); trace!("new_node: inline node {:?}", rlp.pretty());
out.append_raw(&rlp, 1); out.append_raw(&rlp, 1);
} }
} }
@ -178,7 +178,7 @@ impl TrieDB {
fn set_root_rlp(&mut self, root_data: &[u8]) { fn set_root_rlp(&mut self, root_data: &[u8]) {
self.db.kill(&self.root); self.db.kill(&self.root);
self.root = self.db.insert(root_data); self.root = self.db.insert(root_data);
trace!("set_root_rlp {:?} {:?}", root_data, self.root); trace!("set_root_rlp {:?} {:?}", root_data.pretty(), self.root);
} }
fn apply(&mut self, diff: Diff) { fn apply(&mut self, diff: Diff) {
@ -190,7 +190,7 @@ impl TrieDB {
self.db.kill(&h); self.db.kill(&h);
}, },
Operation::New(h, d) => { Operation::New(h, d) => {
trace!("TrieDB::apply +++ {:?} -> {:?}", &h, &d); trace!("TrieDB::apply +++ {:?} -> {:?}", &h, d.pretty());
self.db.emplace(h, d); self.db.emplace(h, d);
} }
} }
@ -250,32 +250,32 @@ impl TrieDB {
} }
fn add(&mut self, key: &NibbleSlice, value: &[u8]) { fn add(&mut self, key: &NibbleSlice, value: &[u8]) {
trace!("ADD: {:?} {:?}", key, value); trace!("ADD: {:?} {:?}", key, value.pretty());
// determine what the new root is, insert new nodes and remove old as necessary. // determine what the new root is, insert new nodes and remove old as necessary.
let mut todo: Diff = Diff::new(); let mut todo: Diff = Diff::new();
let root_rlp = self.augmented(self.db.lookup(&self.root).expect("Trie root not found!"), key, value, &mut todo); let root_rlp = self.augmented(self.db.lookup(&self.root).expect("Trie root not found!"), key, value, &mut todo);
self.apply(todo); self.apply(todo);
self.set_root_rlp(&root_rlp); self.set_root_rlp(&root_rlp);
trace!("---"); trace!("/");
} }
fn compose_leaf(partial: &NibbleSlice, value: &[u8]) -> Bytes { fn compose_leaf(partial: &NibbleSlice, value: &[u8]) -> Bytes {
trace!("compose_leaf {:?} {:?} ({:?})", partial, value, partial.encoded(true)); trace!("compose_leaf {:?} {:?} ({:?})", partial, value.pretty(), partial.encoded(true).pretty());
let mut s = RlpStream::new_list(2); let mut s = RlpStream::new_list(2);
s.append(&partial.encoded(true)); s.append(&partial.encoded(true));
s.append(&value); s.append(&value);
let r = s.out(); let r = s.out();
trace!("compose_leaf: -> {:?}", &r); trace!("compose_leaf: -> {:?}", r.pretty());
r r
} }
fn compose_raw(partial: &NibbleSlice, raw_payload: &[u8], is_leaf: bool) -> Bytes { fn compose_raw(partial: &NibbleSlice, raw_payload: &[u8], is_leaf: bool) -> Bytes {
println!("compose_raw {:?} {:?} {:?} ({:?})", partial, raw_payload, is_leaf, partial.encoded(is_leaf)); println!("compose_raw {:?} {:?} {:?} ({:?})", partial, raw_payload.pretty(), is_leaf, partial.encoded(is_leaf));
let mut s = RlpStream::new_list(2); let mut s = RlpStream::new_list(2);
s.append(&partial.encoded(is_leaf)); s.append(&partial.encoded(is_leaf));
s.append_raw(raw_payload, 1); s.append_raw(raw_payload, 1);
let r = s.out(); let r = s.out();
println!("compose_raw: -> {:?}", &r); println!("compose_raw: -> {:?}", r.pretty());
r r
} }
@ -287,17 +287,18 @@ impl TrieDB {
/// the trie. /// the trie.
fn take_node<'a, 'rlp_view>(&'a self, rlp: &'rlp_view Rlp<'a>, diff: &mut Diff) -> &'a [u8] where 'a: 'rlp_view { fn take_node<'a, 'rlp_view>(&'a self, rlp: &'rlp_view Rlp<'a>, diff: &mut Diff) -> &'a [u8] where 'a: 'rlp_view {
if rlp.is_list() { if rlp.is_list() {
trace!("take_node {:?} (inline)", rlp.raw()); trace!("take_node {:?} (inline)", rlp.raw().pretty());
rlp.raw() rlp.raw()
} }
else if rlp.is_data() && rlp.size() == 32 { else if rlp.is_data() && rlp.size() == 32 {
let h = H256::decode(rlp); let h = H256::decode(rlp);
let r = self.db.lookup(&h).expect("Trie root not found!"); let r = self.db.lookup(&h).expect("Trie root not found!");
trace!("take_node {:?} (indirect for {:?})", rlp.raw(), r); trace!("take_node {:?} (indirect for {:?})", rlp.raw().pretty(), r);
diff.delete_node_sha3(h); diff.delete_node_sha3(h);
r r
} }
else { else {
trace!("take_node {:?} (???)", rlp.raw().pretty());
panic!("Empty or invalid node given?"); panic!("Empty or invalid node given?");
} }
} }
@ -388,7 +389,7 @@ impl TrieDB {
/// ///
/// **This operation will not insert the new node now destroy the original.** /// **This operation will not insert the new node now destroy the original.**
fn augmented(&self, old: &[u8], partial: &NibbleSlice, value: &[u8], diff: &mut Diff) -> Bytes { fn augmented(&self, old: &[u8], partial: &NibbleSlice, value: &[u8], diff: &mut Diff) -> Bytes {
trace!("augmented ({:?}, {:?}, {:?})", old, partial, value); trace!("augmented ({:?}, {:?}, {:?})", old.pretty(), partial, value.pretty());
// already have an extension. either fast_forward, cleve or transmute_to_branch. // already have an extension. either fast_forward, cleve or transmute_to_branch.
let old_rlp = Rlp::new(old); let old_rlp = Rlp::new(old);
match old_rlp.prototype() { match old_rlp.prototype() {
@ -528,7 +529,7 @@ mod tests {
#[test] #[test]
fn test_at_empty() { fn test_at_empty() {
let mut t = TrieDB::new_memory(); let t = TrieDB::new_memory();
assert_eq!(t.at(&[0x5]), None); assert_eq!(t.at(&[0x5]), None);
} }
@ -564,6 +565,7 @@ mod tests {
#[test] #[test]
fn test_at_dog() { fn test_at_dog() {
env_logger::init().unwrap();
let mut t = TrieDB::new_memory(); let mut t = TrieDB::new_memory();
let v: Vec<(Vec<u8>, Vec<u8>)> = vec![ let v: Vec<(Vec<u8>, Vec<u8>)> = vec![
(From::from("do"), From::from("verb")), (From::from("do"), From::from("verb")),
@ -589,12 +591,14 @@ mod tests {
fn playpen() { fn playpen() {
env_logger::init().unwrap(); env_logger::init().unwrap();
let big_value = b"00000000000000000000000000000000";
let mut t = TrieDB::new_memory(); let mut t = TrieDB::new_memory();
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], big_value);
t.insert(&[], &[0x0]); t.insert(&[0x11u8, 0x23], big_value);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![], vec![0x0]), (vec![0x01u8, 0x23], big_value.to_vec()),
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x11u8, 0x23], big_value.to_vec())
])); ]));
} }
@ -643,4 +647,67 @@ mod tests {
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
])); ]));
} }
#[test]
fn insert_value_into_branch_root() {
let mut t = TrieDB::new_memory();
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[], &[0x0]);
assert_eq!(*t.root(), trie_root(vec![
(vec![], vec![0x0]),
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
]));
} }
#[test]
fn insert_split_leaf() {
let mut t = TrieDB::new_memory();
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]);
assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x01u8, 0x34], vec![0x01u8, 0x34]),
]));
}
#[test]
fn insert_split_extenstion() {
let mut t = TrieDB::new_memory();
t.insert(&[0x01, 0x23, 0x45], &[0x01]);
t.insert(&[0x01, 0xf3, 0x45], &[0x02]);
t.insert(&[0x01, 0xf3, 0xf5], &[0x03]);
assert_eq!(*t.root(), trie_root(vec![
(vec![0x01, 0x23, 0x45], vec![0x01]),
(vec![0x01, 0xf3, 0x45], vec![0x02]),
(vec![0x01, 0xf3, 0xf5], vec![0x03]),
]));
}
#[test]
fn insert_big_value() {
let big_value0 = b"00000000000000000000000000000000";
let big_value1 = b"11111111111111111111111111111111";
let mut t = TrieDB::new_memory();
t.insert(&[0x01u8, 0x23], big_value0);
t.insert(&[0x11u8, 0x23], big_value1);
assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], big_value0.to_vec()),
(vec![0x11u8, 0x23], big_value1.to_vec())
]));
}
#[test]
fn insert_duplicate_value() {
let big_value = b"00000000000000000000000000000000";
let mut t = TrieDB::new_memory();
t.insert(&[0x01u8, 0x23], big_value);
t.insert(&[0x11u8, 0x23], big_value);
assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], big_value.to_vec()),
(vec![0x11u8, 0x23], big_value.to_vec())
]));
}
}