multiversx_sc_scenario/executor/debug/
catch_tx_panic.rs1use multiversx_chain_vm::host::context::TxPanic;
2use multiversx_chain_vm_executor::{BreakpointValue, VMHooksEarlyExit};
3use multiversx_sc::{chain_core::types::ReturnCode, err_msg};
4
5pub fn catch_tx_panic<F>(panic_message_flag: bool, f: F) -> Result<(), TxPanic>
11where
12 F: FnOnce() -> Result<(), TxPanic>,
13{
14 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
15 match result {
16 Ok(result) => result,
17 Err(panic_any) => {
18 if panic_any.downcast_ref::<BreakpointValue>().is_some() {
19 Ok(())
21 } else if let Some(early_exit) = panic_any.downcast_ref::<VMHooksEarlyExit>() {
22 if early_exit.code == 0 {
23 Ok(())
24 } else {
25 Err(TxPanic::new(
26 ReturnCode::from_u64(early_exit.code).unwrap(),
27 &early_exit.message,
28 ))
29 }
30 } else {
31 Err(interpret_panic_as_tx_panic(panic_any, panic_message_flag))
33 }
34 }
35 }
36}
37
38fn interpret_panic_as_tx_panic(
41 panic_any: Box<dyn std::any::Any + std::marker::Send>,
42 panic_message_flag: bool,
43) -> TxPanic {
44 if let Some(panic_string) = panic_any.downcast_ref::<String>() {
45 return interpret_panic_str_as_tx_result(panic_string.as_str(), panic_message_flag);
46 }
47
48 if let Some(panic_string) = panic_any.downcast_ref::<&str>() {
49 return interpret_panic_str_as_tx_result(panic_string, panic_message_flag);
50 }
51
52 TxPanic::user_error("unknown panic object")
53}
54
55pub fn interpret_panic_str_as_tx_result(panic_str: &str, panic_message_flag: bool) -> TxPanic {
56 if panic_message_flag {
57 TxPanic::user_error(&format!("panic occurred: {panic_str}"))
58 } else {
59 TxPanic::user_error(err_msg::PANIC_OCCURRED)
60 }
61}