diff --git a/util/patricia_trie/src/lib.rs b/util/patricia_trie/src/lib.rs index 3a1d683c2..d1563becf 100644 --- a/util/patricia_trie/src/lib.rs +++ b/util/patricia_trie/src/lib.rs @@ -67,6 +67,8 @@ pub enum TrieError { InvalidStateRoot(H256), /// Trie item not found in the database, IncompleteDatabase(H256), + /// Corrupt Trie item + DecoderError(rlp::DecoderError), } impl fmt::Display for TrieError { @@ -75,6 +77,7 @@ impl fmt::Display for TrieError { TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {}", root), TrieError::IncompleteDatabase(ref missing) => write!(f, "Database missing expected key: {}", missing), + TrieError::DecoderError(ref err) => write!(f, "Decoding failed with {}", err), } } } @@ -84,10 +87,15 @@ impl error::Error for TrieError { match *self { TrieError::InvalidStateRoot(_) => "Invalid state root", TrieError::IncompleteDatabase(_) => "Incomplete database", + TrieError::DecoderError(ref e) => e.description(), } } } +impl From for Box { + fn from(e: rlp::DecoderError) -> Self { Box::new(TrieError::DecoderError(e)) } +} + /// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries. pub type Result = ::std::result::Result>; diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index 88d2bc66e..2d63f7d00 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).expect("rlp read from db; qed") { + match Node::decoded(node_data)? { Node::Leaf(slice, value) => { return Ok(match slice == key { true => Some(self.query.decode(value)), diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 682f12467..aed683117 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -493,3 +493,30 @@ fn get_len() { assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()), Ok(Some(5))); assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); } + +// Test will work once https://github.com/paritytech/parity/pull/8527 is merged and rlp::decode returns Result instead of panicking +//#[test] +//fn test_lookup_with_corrupt_data_returns_decoder_error() { +// use memorydb::*; +// use super::TrieMut; +// use super::triedbmut::*; +// use rlp; +// use ethereum_types::H512; +// +// let mut memdb = MemoryDB::new(); +// let mut root = H256::new(); +// { +// let mut t = TrieDBMut::new(&mut memdb, &mut root); +// t.insert(b"A", b"ABC").unwrap(); +// t.insert(b"B", b"ABCBA").unwrap(); +// } +// +// let t = TrieDB::new(&memdb, &root).unwrap(); +// +// // query for an invalid data type to trigger an error +// let q = rlp::decode::; +// let lookup = Lookup{ db: t.db, query: q, hash: root }; +// let query_result = lookup.look_up(NibbleSlice::new(b"A")); +// let expected = Box::new(TrieError::DecoderError(::rlp::DecoderError::RlpIsTooShort)); +// assert_eq!(query_result.unwrap_err(), expected); +//} diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index 5113fdc17..7aef6cfbf 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -9,7 +9,7 @@ use std::fmt; use std::error::Error as StdError; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] /// Error concerning the RLP decoder. pub enum DecoderError { /// Data has additional bytes at the end of the valid RLP fragment.