Skip to content

Commit

Permalink
Merge pull request #519 from DarkEld3r/transaction-panic-description-…
Browse files Browse the repository at this point in the history
…ecr-683

Get error description from the transaction panic [ECR-683]
  • Loading branch information
stanislav-tkach committed Feb 25, 2018
2 parents 7782418 + 3193697 commit a3a1e39
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
53 changes: 48 additions & 5 deletions exonum/src/blockchain/transaction.rs
Expand Up @@ -16,6 +16,7 @@

use std::borrow::Cow;
use std::any::Any;
use std::error::Error;
use std::fmt;
use std::u8;

Expand Down Expand Up @@ -245,9 +246,8 @@ impl TransactionError {
}

/// Creates a new `TransactionError` instance from `std::thread::Result`'s `Err`.
pub(crate) fn from_panic(_panic: &Box<Any + Send>) -> Self {
// TODO: Try to get description from panic.
Self::panic(None)
pub(crate) fn from_panic(panic: &Box<Any + Send>) -> Self {
Self::panic(panic_description(panic))
}

/// Returns error type of this `TransactionError` instance.
Expand Down Expand Up @@ -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.
Expand All @@ -353,7 +352,6 @@ pub trait TransactionSet
fn tx_from_raw(raw: RawTransaction) -> Result<Self, encoding::Error>;
}


/// `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
Expand Down Expand Up @@ -540,13 +538,26 @@ macro_rules! transactions {
};
}

/// Tries to get a meaningful description from the given panic.
fn panic_description(any: &Box<Any + Send>) -> Option<String> {
if let Some(s) = any.downcast_ref::<&str>() {
Some(s.to_string())
} else if let Some(s) = any.downcast_ref::<String>() {
Some(s.clone())
} else if let Some(error) = any.downcast_ref::<Box<Error + Send>>() {
Some(error.description().to_string())
} else {
None
}
}

#[cfg(test)]
mod tests {
use futures::sync::mpsc;

use std::collections::BTreeMap;
use std::sync::Mutex;
use std::panic;

use super::*;
use crypto;
Expand Down Expand Up @@ -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<Error + Send> = Box::new("e".parse::<i32>().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<T: Send + 'static>(val: T) -> Box<Any + Send> {
panic::catch_unwind(panic::AssertUnwindSafe(|| panic!(val))).unwrap_err()
}

fn create_blockchain() -> (Blockchain, BTreeMap<Hash, Box<Transaction>>) {
let service_keypair = crypto::gen_keypair();
let api_channel = mpsc::channel(1);
Expand Down
2 changes: 1 addition & 1 deletion testkit/tests/counter/main.rs
Expand Up @@ -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" }),
);
}

Expand Down

0 comments on commit a3a1e39

Please sign in to comment.