Implement recursive Debug for Nodes in patrica_trie::TrieDB (#8697)

fixes #8184
This commit is contained in:
Benjamin Kampmann 2018-05-25 13:19:32 +02:00 committed by Marek Kotewicz
parent 80528c5344
commit 7d7d4822a5

View File

@ -78,64 +78,9 @@ impl<'db> TrieDB<'db> {
/// Get the data of the root node. /// Get the data of the root node.
fn root_data(&self) -> super::Result<DBValue> { fn root_data(&self) -> super::Result<DBValue> {
self.db.get(self.root).ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) self.db
} .get(self.root)
.ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root)))
/// Indentation helper for `format_all`.
fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result {
for _ in 0..size {
write!(f, " ")?;
}
Ok(())
}
/// Recursion helper for implementation of formatting trait.
fn fmt_all(&self, node: Node, f: &mut fmt::Formatter, deepness: usize) -> fmt::Result {
match node {
Node::Leaf(slice, value) => writeln!(f, "'{:?}: {:?}.", slice, value.pretty())?,
Node::Extension(ref slice, ref item) => {
write!(f, "'{:?} ", slice)?;
if let Ok(node) = self.get_raw_or_lookup(&*item) {
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) => {
writeln!(f, "")?;
if let Some(ref v) = *value {
self.fmt_indent(f, deepness + 1)?;
writeln!(f, "=: {:?}", v.pretty())?
}
for i in 0..16 {
let node = self.get_raw_or_lookup(&*nodes[i]);
match node.as_ref() {
Ok(n) => {
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)?;
}
}
}
},
// empty
Node::Empty => {
writeln!(f, "<empty>")?;
}
};
Ok(())
} }
/// Given some node-describing data `node`, return the actual node RLP. /// Given some node-describing data `node`, return the actual node RLP.
@ -174,15 +119,58 @@ impl<'db> Trie for TrieDB<'db> {
} }
} }
// This is for pretty debug output only
struct TrieAwareDebugNode<'db, 'a> {
trie: &'db TrieDB<'db>,
key: &'a[u8]
}
impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Ok(node) = self.trie.get_raw_or_lookup(self.key) {
match Node::decoded(&node) {
Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf")
.field("slice", &slice)
.field("value", &value)
.finish(),
Ok(Node::Extension(ref slice, ref item)) => f.debug_struct("Node::Extension")
.field("slice", &slice)
.field("item", &TrieAwareDebugNode{trie: self.trie, key: item})
.finish(),
Ok(Node::Branch(ref nodes, ref value)) => {
let nodes: Vec<TrieAwareDebugNode> = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect();
f.debug_struct("Node::Branch")
.field("nodes", &nodes)
.field("value", &value)
.finish()
},
Ok(Node::Empty) => f.debug_struct("Node::Empty").finish(),
Err(e) => f.debug_struct("BROKEN_NODE")
.field("key", &self.key)
.field("error", &format!("ERROR decoding node branch Rlp: {}", e))
.finish()
}
} else {
f.debug_struct("BROKEN_NODE")
.field("key", &self.key)
.field("error", &"Not found")
.finish()
}
}
}
impl<'db> fmt::Debug for TrieDB<'db> { impl<'db> fmt::Debug for TrieDB<'db> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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!"); let root_rlp = self.db.get(self.root).expect("Trie root not found!");
match Node::decoded(&root_rlp) { f.debug_struct("TrieDB")
Ok(node) => self.fmt_all(node, f, 0)?, .field("hash_count", &self.hash_count)
Err(e) => writeln!(f, "ERROR decoding node rlp: {}", e)?, .field("root", &TrieAwareDebugNode {
} trie: self,
writeln!(f, "]") key: &root_rlp
})
.finish()
} }
} }
@ -494,6 +482,118 @@ fn get_len() {
assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None));
} }
#[test]
fn debug_output_supports_pretty_print() {
use memorydb::*;
use super::TrieMut;
use super::triedbmut::*;
let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ];
let mut memdb = MemoryDB::new();
let mut root = H256::new();
let root = {
let mut t = TrieDBMut::new(&mut memdb, &mut root);
for x in &d {
t.insert(x, x).unwrap();
}
t.root().clone()
};
let t = TrieDB::new(&memdb, &root).unwrap();
assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }");
assert_eq!(format!("{:#?}", t),
"TrieDB {
hash_count: 0,
root: Node::Extension {
slice: 4,
item: Node::Branch {
nodes: [
Node::Empty,
Node::Branch {
nodes: [
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Branch {
nodes: [
Node::Empty,
Node::Leaf {
slice: ,
value: [
65,
65
]
},
Node::Leaf {
slice: ,
value: [
65,
66
]
},
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty
],
value: None
},
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty
],
value: Some(
[
65
]
)
},
Node::Leaf {
slice: ,
value: [
66
]
},
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty,
Node::Empty
],
value: None
}
}
}");
}
// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking // Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking
//#[test] //#[test]
//fn test_lookup_with_corrupt_data_returns_decoder_error() { //fn test_lookup_with_corrupt_data_returns_decoder_error() {