Skip to content

Commit d74b89b

Browse files
committed
Merge branch 'fix/get-chain-height-chain-type'
2 parents 931062f + 2738978 commit d74b89b

1 file changed

Lines changed: 110 additions & 28 deletions

File tree

rust/src/lib.rs

Lines changed: 110 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::cmp::Ordering;
22
use std::os::raw::c_char;
33
use std::ffi::{CString, CStr, c_void};
4-
use std::path::Path;
4+
use std::path::{Path, PathBuf};
55
use std::sync::Arc;
6+
use std::sync::Once;
67
use rand::thread_rng;
78
use serde::{Deserialize, Serialize};
89
use uuid::Uuid;
@@ -102,6 +103,57 @@ macro_rules! ensure_wallet (
102103
)
103104
);
104105

106+
static PANIC_HOOK_INIT: Once = Once::new();
107+
108+
// Appends panics to ~/.stackwallet/flutter_libmwc-panic.log so worker-thread
109+
// panics that bypass stderr still leave a trail.
110+
fn install_panic_hook() {
111+
PANIC_HOOK_INIT.call_once(|| {
112+
let log_path = std::env::var_os("HOME")
113+
.map(PathBuf::from)
114+
.map(|p| p.join(".stackwallet/flutter_libmwc-panic.log"))
115+
.unwrap_or_else(|| PathBuf::from("/tmp/flutter_libmwc-panic.log"));
116+
if let Some(parent) = log_path.parent() {
117+
let _ = std::fs::create_dir_all(parent);
118+
}
119+
let previous = std::panic::take_hook();
120+
std::panic::set_hook(Box::new(move |info| {
121+
let payload = info.payload();
122+
let msg = if let Some(s) = payload.downcast_ref::<&str>() {
123+
(*s).to_string()
124+
} else if let Some(s) = payload.downcast_ref::<String>() {
125+
s.clone()
126+
} else {
127+
"<non-string panic payload>".to_string()
128+
};
129+
let location = info.location()
130+
.map(|l| format!("{}:{}:{}", l.file(), l.line(), l.column()))
131+
.unwrap_or_else(|| "<unknown>".to_string());
132+
let backtrace = std::backtrace::Backtrace::force_capture();
133+
let timestamp = std::time::SystemTime::now()
134+
.duration_since(std::time::UNIX_EPOCH)
135+
.map(|d| d.as_secs())
136+
.unwrap_or(0);
137+
let thread = std::thread::current();
138+
let thread_name = thread.name().unwrap_or("<unnamed>");
139+
let entry = format!(
140+
"\n=== flutter_libmwc panic at unix={} ===\nthread: {}\nlocation: {}\nmessage: {}\nbacktrace:\n{}\n",
141+
timestamp, thread_name, location, msg, backtrace,
142+
);
143+
if let Ok(mut f) = std::fs::OpenOptions::new()
144+
.create(true)
145+
.append(true)
146+
.open(&log_path)
147+
{
148+
use std::io::Write;
149+
let _ = f.write_all(entry.as_bytes());
150+
let _ = f.flush();
151+
}
152+
previous(info);
153+
}));
154+
});
155+
}
156+
105157

106158
fn init_logger() {
107159
android_logger::init_once(
@@ -276,6 +328,7 @@ pub unsafe extern "C" fn mwc_rust_open_wallet(
276328
config: *const c_char,
277329
password: *const c_char,
278330
) -> *const c_char {
331+
install_panic_hook();
279332
//init_logger();
280333
let result = match _open_wallet(
281334
config,
@@ -475,36 +528,49 @@ pub unsafe extern "C" fn mwc_rust_wallet_scan_outputs(
475528
start_height: *const c_char,
476529
number_of_blocks: *const c_char,
477530
) -> *const c_char {
478-
let wallet_ptr = CStr::from_ptr(wallet);
479-
let c_start_height = CStr::from_ptr(start_height);
480-
let c_number_of_blocks = CStr::from_ptr(number_of_blocks);
481-
let start_height: u64 = c_start_height.to_str().unwrap().to_string().parse().unwrap();
482-
let number_of_blocks: u64 = c_number_of_blocks.to_str().unwrap().to_string().parse().unwrap();
483-
484-
let wallet_data = wallet_ptr.to_str().unwrap();
485-
let tuple_wallet_data: (u64, Option<SecretKey>) = serde_json::from_str(wallet_data).unwrap();
486-
let wlt = tuple_wallet_data.0;
487-
let sek_key = tuple_wallet_data.1;
488-
489-
ensure_wallet!(wlt, wallet);
531+
install_panic_hook();
532+
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
533+
let wallet_ptr = CStr::from_ptr(wallet);
534+
let c_start_height = CStr::from_ptr(start_height);
535+
let c_number_of_blocks = CStr::from_ptr(number_of_blocks);
536+
let start_height: u64 = c_start_height.to_str().unwrap().to_string().parse().unwrap();
537+
let number_of_blocks: u64 = c_number_of_blocks.to_str().unwrap().to_string().parse().unwrap();
538+
539+
let wallet_data = wallet_ptr.to_str().unwrap();
540+
let tuple_wallet_data: (u64, Option<SecretKey>) = serde_json::from_str(wallet_data).unwrap();
541+
let wlt = tuple_wallet_data.0;
542+
let sek_key = tuple_wallet_data.1;
490543

491-
let result = match _wallet_scan_outputs(
492-
wallet,
493-
sek_key,
494-
start_height,
495-
number_of_blocks
496-
) {
497-
Ok(scan) => {
498-
scan
499-
}, Err(e ) => {
500-
let error_msg = format!("Error {}", &e.to_string());
501-
let error_msg_ptr = CString::new(error_msg).unwrap();
502-
let ptr = error_msg_ptr.as_ptr(); // Get a pointer to the underlaying memory for s
503-
std::mem::forget(error_msg_ptr);
544+
ensure_wallet!(wlt, wallet);
545+
546+
match _wallet_scan_outputs(
547+
wallet,
548+
sek_key,
549+
start_height,
550+
number_of_blocks
551+
) {
552+
Ok(scan) => scan,
553+
Err(e) => {
554+
let error_msg = format!("Error {}", &e.to_string());
555+
let error_msg_ptr = CString::new(error_msg).unwrap();
556+
let ptr = error_msg_ptr.as_ptr();
557+
std::mem::forget(error_msg_ptr);
558+
ptr
559+
}
560+
}
561+
}));
562+
match result {
563+
Ok(ptr) => ptr,
564+
Err(_) => {
565+
let error_msg = CString::new(
566+
"Error scanOutputs panicked; see flutter_libmwc-panic.log",
567+
)
568+
.unwrap();
569+
let ptr = error_msg.as_ptr();
570+
std::mem::forget(error_msg);
504571
ptr
505572
}
506-
};
507-
result
573+
}
508574
}
509575

510576
fn _wallet_scan_outputs(
@@ -751,6 +817,7 @@ fn _tx_cancel(
751817
pub unsafe extern "C" fn mwc_rust_get_chain_height(
752818
config: *const c_char,
753819
) -> *const c_char {
820+
install_panic_hook();
754821
let result = match _get_chain_height(
755822
config
756823
) {
@@ -1376,6 +1443,13 @@ pub fn get_chain_height(config: &str) -> Result<u64, Error> {
13761443
return Err(e);
13771444
}
13781445
};
1446+
// get_chain_tip reads chain type; init it here since this entry point
1447+
// can fire before any get_wallet call.
1448+
let target_chaintype = wallet_config.chain_type.unwrap_or(ChainTypes::Mainnet);
1449+
global::set_global_chain_type(target_chaintype);
1450+
if global::get_chain_type() != target_chaintype {
1451+
global::set_local_chain_type(target_chaintype);
1452+
};
13791453
let node_api_secret = get_first_line(wallet_config.node_api_secret_path.clone());
13801454
let node_client = HTTPNodeClient::new(vec![wallet_config.check_node_api_http_addr], node_api_secret)
13811455
.map_err(|e| Error::ClientCallback(format!("{}", e)))?;
@@ -1902,6 +1976,13 @@ impl Task for Listener {
19021976
type Output = usize;
19031977

19041978
fn run(&self, cancel_tok: &CancellationToken) -> Result<Self::Output, anyhow::Error> {
1979+
install_panic_hook();
1980+
// export_task! runs us on a fresh thread; seed CHAIN_TYPE for it.
1981+
let target_chaintype = ChainTypes::Mainnet;
1982+
global::set_global_chain_type(target_chaintype);
1983+
if global::get_chain_type() != target_chaintype {
1984+
global::set_local_chain_type(target_chaintype);
1985+
}
19051986
let mut spins = 0;
19061987
let tuple_wallet_data: (u64, Option<SecretKey>) = serde_json::from_str(&self.wallet_ptr_str)?;
19071988
let wlt = tuple_wallet_data.0;
@@ -1947,6 +2028,7 @@ pub unsafe extern "C" fn mwc_rust_mwcmqs_listener_start(
19472028
wallet: *const c_char,
19482029
mwcmqs_config: *const c_char,
19492030
) -> *mut c_void {
2031+
install_panic_hook();
19502032
let wallet_ptr = CStr::from_ptr(wallet);
19512033
let mwcmqs_config = CStr::from_ptr(mwcmqs_config);
19522034
let mwcmqs_config = mwcmqs_config.to_str().unwrap();

0 commit comments

Comments
 (0)