From 148589a39e3abbeb0219d8964a02ca474ddcb80c Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Fri, 23 Feb 2018 18:26:05 +0200 Subject: [PATCH 1/2] Get error description from the transaction panic --- exonum/src/blockchain/transaction.rs | 53 +++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/exonum/src/blockchain/transaction.rs b/exonum/src/blockchain/transaction.rs index 925c43914c..64e6804167 100644 --- a/exonum/src/blockchain/transaction.rs +++ b/exonum/src/blockchain/transaction.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; use std::any::Any; +use std::error::Error; use std::fmt; use std::u8; @@ -245,9 +246,8 @@ impl TransactionError { } /// Creates a new `TransactionError` instance from `std::thread::Result`'s `Err`. - pub(crate) fn from_panic(_panic: &Box) -> Self { - // TODO: Try to get description from panic. - Self::panic(None) + pub(crate) fn from_panic(panic: &Box) -> Self { + Self::panic(panic_description(panic)) } /// Returns error type of this `TransactionError` instance. @@ -343,7 +343,6 @@ fn status_as_u16(status: &TransactionResult) -> u16 { } } - /// `TransactionSet` trait describes a type which is an `enum` of several transactions. /// The implementation of this trait is generated automatically by the `transactions!` /// macro. @@ -353,7 +352,6 @@ pub trait TransactionSet fn tx_from_raw(raw: RawTransaction) -> Result; } - /// `transactions!` is used to declare a set of transactions of a particular service. /// /// The macro generates a type for each transaction and a helper enum which can hold @@ -540,6 +538,18 @@ macro_rules! transactions { }; } +/// Tries to get a meaningful description from the given panic. +fn panic_description(any: &Box) -> Option { + if let Some(s) = any.downcast_ref::<&str>() { + Some(s.to_string()) + } else if let Some(s) = any.downcast_ref::() { + Some(s.clone()) + } else if let Some(error) = any.downcast_ref::>() { + Some(error.description().to_string()) + } else { + None + } +} #[cfg(test)] mod tests { @@ -547,6 +557,7 @@ mod tests { use std::collections::BTreeMap; use std::sync::Mutex; + use std::panic; use super::*; use crypto; @@ -704,6 +715,38 @@ mod tests { } } + #[test] + fn str_panic() { + let static_str = "Static string (&str)"; + let panic = make_panic(static_str); + assert_eq!(Some(static_str.to_string()), panic_description(&panic)); + } + + #[test] + fn string_panic() { + let string = "Owned string (String)".to_owned(); + let error = make_panic(string.clone()); + assert_eq!(Some(string), panic_description(&error)); + } + + #[test] + fn box_error_panic() { + let error: Box = Box::new("e".parse::().unwrap_err()); + let description = error.description().to_owned(); + let error = make_panic(error); + assert_eq!(Some(description), panic_description(&error)); + } + + #[test] + fn unknown_panic() { + let error = make_panic(1); + assert_eq!(None, panic_description(&error)); + } + + fn make_panic(val: T) -> Box { + panic::catch_unwind(panic::AssertUnwindSafe(|| panic!(val))).unwrap_err() + } + fn create_blockchain() -> (Blockchain, BTreeMap>) { let service_keypair = crypto::gen_keypair(); let api_channel = mpsc::channel(1); From a311b63d299b71bb5ba025ffdf91b811040bb432 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Sun, 25 Feb 2018 01:26:10 +0200 Subject: [PATCH 2/2] Update testkit test --- testkit/tests/counter/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testkit/tests/counter/main.rs b/testkit/tests/counter/main.rs index 7295bdd443..3e3008babe 100644 --- a/testkit/tests/counter/main.rs +++ b/testkit/tests/counter/main.rs @@ -641,7 +641,7 @@ fn test_explorer_transaction_statuses() { assert_status( &api, &panicking_tx, - &json!({ "type": "panic", "description": "" }), + &json!({ "type": "panic", "description": "attempt to add with overflow" }), ); }