Implement recursive Debug for Nodes in patrica_trie::TrieDB (#8697)
fixes #8184
This commit is contained in:
parent
80528c5344
commit
7d7d4822a5
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user