@@ -7,12 +7,54 @@ use bdk_core::{
77 BlockId , CheckPoint , ConfirmationBlockTime , Indexed , TxUpdate ,
88} ;
99use esplora_client:: { OutputStatus , Tx } ;
10+ use std:: any:: Any ;
11+ use std:: fmt;
1012use std:: thread:: JoinHandle ;
1113
1214use crate :: { insert_anchor_or_seen_at_from_status, insert_prevouts} ;
1315
14- /// [`esplora_client::Error`]
15- pub type Error = Box < esplora_client:: Error > ;
16+ #[ derive( Debug ) ]
17+ pub enum Error {
18+ Client ( esplora_client:: Error ) ,
19+ ThreadPanic ( Option < String > ) ,
20+ }
21+
22+ impl Error {
23+ fn from_thread_panic ( err : Box < dyn Any + Send > ) -> Self {
24+ if let Ok ( msg) = err. downcast :: < String > ( ) {
25+ Self :: ThreadPanic ( Some ( * msg) )
26+ } else if let Ok ( msg) = err. downcast :: < & ' static str > ( ) {
27+ Self :: ThreadPanic ( Some ( msg. to_string ( ) ) )
28+ } else {
29+ Self :: ThreadPanic ( None )
30+ }
31+ }
32+ }
33+
34+ impl From < esplora_client:: Error > for Error {
35+ fn from ( err : esplora_client:: Error ) -> Self {
36+ Self :: Client ( err)
37+ }
38+ }
39+
40+ impl fmt:: Display for Error {
41+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
42+ match self {
43+ Self :: Client ( err) => write ! ( f, "{err}" ) ,
44+ Self :: ThreadPanic ( Some ( msg) ) => write ! ( f, "worker thread panicked: {msg}" ) ,
45+ Self :: ThreadPanic ( None ) => write ! ( f, "worker thread panicked" ) ,
46+ }
47+ }
48+ }
49+
50+ impl std:: error:: Error for Error {
51+ fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
52+ match self {
53+ Self :: Client ( err) => Some ( err) ,
54+ _ => None ,
55+ }
56+ }
57+ }
1658
1759/// Trait to extend the functionality of [`esplora_client::BlockingClient`].
1860///
@@ -241,15 +283,13 @@ fn chain_update(
241283 let mut tip = match point_of_agreement {
242284 Some ( tip) => tip,
243285 None => {
244- return Err ( Box :: new ( esplora_client:: Error :: HeaderHashNotFound (
245- local_cp_hash,
246- ) ) ) ;
286+ return Err ( esplora_client:: Error :: HeaderHashNotFound ( local_cp_hash) . into ( ) ) ;
247287 }
248288 } ;
249289
250290 tip = tip
251291 . extend ( conflicts. into_iter ( ) . rev ( ) . map ( |b| ( b. height , b. hash ) ) )
252- . map_err ( |_| Box :: new ( esplora_client:: Error :: InvalidResponse ) ) ?;
292+ . map_err ( |_| Error :: from ( esplora_client:: Error :: InvalidResponse ) ) ?;
253293
254294 for ( anchor, _) in anchors {
255295 let height = anchor. block_id . height ;
@@ -319,15 +359,15 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<SpkWithExpectedTxids>
319359
320360 if handles. is_empty ( ) {
321361 if !processed_any {
322- return Err ( Box :: new ( esplora_client:: Error :: InvalidResponse ) ) ;
362+ return Err ( esplora_client:: Error :: InvalidResponse . into ( ) ) ;
323363 }
324364 break ;
325365 }
326366
327367 for handle in handles {
328368 let handle_result = handle
329369 . join ( )
330- . map_err ( |_| Box :: new ( esplora_client :: Error :: InvalidResponse ) ) ?;
370+ . map_err ( Error :: from_thread_panic ) ?;
331371 let ( index, txs, evicted) = handle_result?;
332372 processed_any = true ;
333373 if txs. is_empty ( ) {
@@ -411,7 +451,7 @@ fn fetch_txs_with_txids<I: IntoIterator<Item = Txid>>(
411451 std:: thread:: spawn ( move || {
412452 client
413453 . get_tx_info ( & txid)
414- . map_err ( Box :: new )
454+ . map_err ( Error :: from )
415455 . map ( |t| ( txid, t) )
416456 } )
417457 } )
@@ -424,7 +464,7 @@ fn fetch_txs_with_txids<I: IntoIterator<Item = Txid>>(
424464 for handle in handles {
425465 let handle_result = handle
426466 . join ( )
427- . map_err ( |_| Box :: new ( esplora_client :: Error :: InvalidResponse ) ) ?;
467+ . map_err ( Error :: from_thread_panic ) ?;
428468 let ( txid, tx_info) = handle_result?;
429469 if let Some ( tx_info) = tx_info {
430470 if inserted_txs. insert ( txid) {
@@ -476,7 +516,7 @@ fn fetch_txs_with_outpoints<I: IntoIterator<Item = OutPoint>>(
476516 std:: thread:: spawn ( move || {
477517 client
478518 . get_output_status ( & op. txid , op. vout as _ )
479- . map_err ( Box :: new )
519+ . map_err ( Error :: from )
480520 } )
481521 } )
482522 . collect :: < Vec < JoinHandle < Result < Option < OutputStatus > , Error > > > > ( ) ;
@@ -488,7 +528,7 @@ fn fetch_txs_with_outpoints<I: IntoIterator<Item = OutPoint>>(
488528 for handle in handles {
489529 let handle_result = handle
490530 . join ( )
491- . map_err ( |_| Box :: new ( esplora_client :: Error :: InvalidResponse ) ) ?;
531+ . map_err ( Error :: from_thread_panic ) ?;
492532 if let Some ( op_status) = handle_result? {
493533 let spend_txid = match op_status. txid {
494534 Some ( txid) => txid,
@@ -549,24 +589,23 @@ mod test {
549589 let res = ( || -> Result < ( ) , Error > {
550590 let handle_result = handle
551591 . join ( )
552- . map_err ( |_| Box :: new ( esplora_client:: Error :: InvalidResponse ) ) ?;
553- handle_result?;
554- Ok ( ( ) )
592+ . map_err ( Error :: from_thread_panic) ?;
593+ handle_result
555594 } ) ( ) ;
556595
557596 assert ! ( matches!(
558- * res. unwrap_err( ) ,
559- esplora_client :: Error :: InvalidResponse
597+ res. unwrap_err( ) ,
598+ Error :: ThreadPanic ( _ )
560599 ) ) ;
561600 }
562601
563602 #[ test]
564603 fn ensure_last_index_none_returns_error ( ) {
565604 let last_index: Option < u32 > = None ;
566605 let err = last_index
567- . ok_or_else ( || Box :: new ( esplora_client:: Error :: InvalidResponse ) )
606+ . ok_or_else ( || Error :: from ( esplora_client:: Error :: InvalidResponse ) )
568607 . unwrap_err ( ) ;
569- assert ! ( matches!( * err, esplora_client:: Error :: InvalidResponse ) ) ;
608+ assert ! ( matches!( err, Error :: Client ( esplora_client:: Error :: InvalidResponse ) ) ) ;
570609 }
571610
572611 macro_rules! local_chain {
0 commit comments