@@ -44,6 +44,7 @@ use bitcoin::BlockHash;
4444
4545use std:: convert:: TryInto ;
4646use std:: default:: Default ;
47+ use std:: fmt;
4748use std:: fs;
4849use std:: sync:: { Arc , Mutex , RwLock } ;
4950use std:: time:: SystemTime ;
@@ -66,6 +67,42 @@ enum GossipSourceConfig {
6667 RapidGossipSync ( String ) ,
6768}
6869
70+ /// An error encountered during building a [`Node`].
71+ ///
72+ /// [`Node`]: crate::Node
73+ #[ derive( Debug , Clone ) ]
74+ pub enum BuildError {
75+ /// The given seed bytes are invalid, e.g, are of invalid length.
76+ InvalidSeedBytes ,
77+ /// The current system time is invalid, clocks might have gone backwards.
78+ InvalidSystemTime ,
79+ /// We failed to read data from the [`KVStore`].
80+ IOReadFailed ,
81+ /// We failed to write data to the [`KVStore`].
82+ IOWriteFailed ,
83+ /// We failed to access the given `storage_dir_path`.
84+ StoragePathAccessFailed ,
85+ /// We failed to setup the onchain wallet.
86+ WalletSetupFailed ,
87+ }
88+
89+ impl fmt:: Display for BuildError {
90+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
91+ match * self {
92+ Self :: InvalidSeedBytes => write ! ( f, "Given seed bytes are invalid." ) ,
93+ Self :: InvalidSystemTime => {
94+ write ! ( f, "System time is invalid. Clocks might have gone back in time." )
95+ }
96+ Self :: IOReadFailed => write ! ( f, "Failed to read from store." ) ,
97+ Self :: IOWriteFailed => write ! ( f, "Failed to write to store." ) ,
98+ Self :: StoragePathAccessFailed => write ! ( f, "Failed to access the given storage path." ) ,
99+ Self :: WalletSetupFailed => write ! ( f, "Failed to setup onchain wallet." ) ,
100+ }
101+ }
102+ }
103+
104+ impl std:: error:: Error for BuildError { }
105+
69106/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
70107/// the getgo.
71108///
@@ -111,13 +148,14 @@ impl NodeBuilder {
111148 /// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
112149 ///
113150 /// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
114- pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) {
151+ pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) -> Result < ( ) , BuildError > {
115152 if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
116- panic ! ( "Failed to set seed due to invalid length." ) ;
153+ return Err ( BuildError :: InvalidSeedBytes ) ;
117154 }
118155 let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
119156 bytes. copy_from_slice ( & seed_bytes) ;
120157 self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
158+ Ok ( ( ) )
121159 }
122160
123161 /// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -167,26 +205,28 @@ impl NodeBuilder {
167205
168206 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
169207 /// previously configured.
170- pub fn build ( & self ) -> Node < SqliteStore > {
208+ pub fn build ( & self ) -> Result < Node < SqliteStore > , BuildError > {
171209 let storage_dir_path = self . config . storage_dir_path . clone ( ) ;
172- fs:: create_dir_all ( storage_dir_path. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
210+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
211+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
173212 let kv_store = Arc :: new ( SqliteStore :: new ( storage_dir_path. into ( ) ) ) ;
174213 self . build_with_store ( kv_store)
175214 }
176215
177216 /// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
178217 /// previously configured.
179- pub fn build_with_fs_store ( & self ) -> Node < FilesystemStore > {
218+ pub fn build_with_fs_store ( & self ) -> Result < Node < FilesystemStore > , BuildError > {
180219 let storage_dir_path = self . config . storage_dir_path . clone ( ) ;
181- fs:: create_dir_all ( storage_dir_path. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
220+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
221+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
182222 let kv_store = Arc :: new ( FilesystemStore :: new ( storage_dir_path. into ( ) ) ) ;
183223 self . build_with_store ( kv_store)
184224 }
185225
186226 /// Builds a [`Node`] instance according to the options previously configured.
187227 pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
188228 & self , kv_store : Arc < K > ,
189- ) -> Node < K > {
229+ ) -> Result < Node < K > , BuildError > {
190230 let config = Arc :: new ( self . config . clone ( ) ) ;
191231
192232 let runtime = Arc :: new ( RwLock :: new ( None ) ) ;
@@ -239,7 +279,7 @@ impl ArcedNodeBuilder {
239279 /// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
240280 ///
241281 /// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
242- pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) {
282+ pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) -> Result < ( ) , BuildError > {
243283 self . inner . write ( ) . unwrap ( ) . set_entropy_seed_bytes ( seed_bytes)
244284 }
245285
@@ -289,21 +329,21 @@ impl ArcedNodeBuilder {
289329
290330 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
291331 /// previously configured.
292- pub fn build ( & self ) -> Arc < Node < SqliteStore > > {
293- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build ( ) )
332+ pub fn build ( & self ) -> Result < Arc < Node < SqliteStore > > , BuildError > {
333+ self . inner . read ( ) . unwrap ( ) . build ( ) . map ( Arc :: new )
294334 }
295335
296336 /// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
297337 /// previously configured.
298- pub fn build_with_fs_store ( & self ) -> Arc < Node < FilesystemStore > > {
299- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) )
338+ pub fn build_with_fs_store ( & self ) -> Result < Arc < Node < FilesystemStore > > , BuildError > {
339+ self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) . map ( Arc :: new )
300340 }
301341
302342 /// Builds a [`Node`] instance according to the options previously configured.
303343 pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
304344 & self , kv_store : Arc < K > ,
305- ) -> Arc < Node < K > > {
306- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) )
345+ ) -> Result < Arc < Node < K > > , BuildError > {
346+ self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) . map ( Arc :: new )
307347 }
308348}
309349
@@ -313,12 +353,12 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
313353 chain_data_source_config : Option < & ' a ChainDataSourceConfig > ,
314354 gossip_source_config : Option < & ' a GossipSourceConfig > , kv_store : Arc < K > ,
315355 runtime : Arc < RwLock < Option < tokio:: runtime:: Runtime > > > ,
316- ) -> Node < K > {
356+ ) -> Result < Node < K > , BuildError > {
317357 let ldk_data_dir = format ! ( "{}/ldk" , config. storage_dir_path) ;
318- fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
358+ fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
319359
320360 let bdk_data_dir = format ! ( "{}/bdk" , config. storage_dir_path) ;
321- fs:: create_dir_all ( bdk_data_dir. clone ( ) ) . expect ( "Failed to create BDK data directory" ) ;
361+ fs:: create_dir_all ( bdk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
322362
323363 // Initialize the Logger
324364 let log_file_path = format ! (
@@ -346,15 +386,15 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
346386 } ;
347387
348388 let xprv = bitcoin:: util:: bip32:: ExtendedPrivKey :: new_master ( config. network , & seed_bytes)
349- . expect ( "Failed to read wallet master key" ) ;
389+ . map_err ( |_| BuildError :: InvalidSeedBytes ) ? ;
350390
351391 let wallet_name = bdk:: wallet:: wallet_name_from_descriptor (
352392 Bip84 ( xprv, bdk:: KeychainKind :: External ) ,
353393 Some ( Bip84 ( xprv, bdk:: KeychainKind :: Internal ) ) ,
354394 config. network ,
355395 & Secp256k1 :: new ( ) ,
356396 )
357- . expect ( "Failed to derive on-chain wallet name" ) ;
397+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
358398
359399 let database_path = format ! ( "{}/bdk_wallet_{}.sqlite" , config. storage_dir_path, wallet_name) ;
360400 let database = SqliteDatabase :: new ( database_path) ;
@@ -365,7 +405,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
365405 config. network ,
366406 database,
367407 )
368- . expect ( "Failed to set up on-chain wallet" ) ;
408+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
369409
370410 let ( blockchain, tx_sync) = match chain_data_source_config {
371411 Some ( ChainDataSourceConfig :: Esplora ( server_url) ) => {
@@ -401,7 +441,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
401441 // Initialize the KeysManager
402442 let cur_time = SystemTime :: now ( )
403443 . duration_since ( SystemTime :: UNIX_EPOCH )
404- . expect ( "System time error: Clock may have gone backwards" ) ;
444+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
405445 let ldk_seed_bytes: [ u8 ; 32 ] = xprv. private_key . secret_bytes ( ) ;
406446 let keys_manager = Arc :: new ( KeysManager :: new (
407447 & ldk_seed_bytes,
@@ -418,7 +458,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
418458 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
419459 Arc :: new ( NetworkGraph :: new ( config. network , Arc :: clone ( & logger) ) )
420460 } else {
421- panic ! ( "Failed to read network graph: {}" , e . to_string ( ) ) ;
461+ return Err ( BuildError :: IOReadFailed ) ;
422462 }
423463 }
424464 } ;
@@ -438,7 +478,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
438478 Arc :: clone ( & logger) ,
439479 ) ) )
440480 } else {
441- panic ! ( "Failed to read scorer: {}" , e . to_string ( ) ) ;
481+ return Err ( BuildError :: IOReadFailed ) ;
442482 }
443483 }
444484 } ;
@@ -462,7 +502,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
462502 Vec :: new ( )
463503 } else {
464504 log_error ! ( logger, "Failed to read channel monitors: {}" , e. to_string( ) ) ;
465- panic ! ( "Failed to read channel monitors: {}" , e . to_string ( ) ) ;
505+ return Err ( BuildError :: IOReadFailed ) ;
466506 }
467507 }
468508 } ;
@@ -489,8 +529,10 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
489529 channel_monitor_references,
490530 ) ;
491531 let ( _hash, channel_manager) =
492- <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args)
493- . expect ( "Failed to read channel manager from store" ) ;
532+ <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args) . map_err ( |e| {
533+ log_error ! ( logger, "Failed to read channel manager from KVStore: {}" , e) ;
534+ BuildError :: IOReadFailed
535+ } ) ?;
494536 channel_manager
495537 } else {
496538 // We're starting a fresh node.
@@ -535,7 +577,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
535577
536578 let cur_time = SystemTime :: now ( )
537579 . duration_since ( SystemTime :: UNIX_EPOCH )
538- . expect ( "System time error: Clock may have gone backwards" ) ;
580+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
539581
540582 // Initialize the GossipSource
541583 // Use the configured gossip source, if the user set one, otherwise default to P2PNetwork.
@@ -552,7 +594,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
552594 Arc :: clone ( & kv_store) ,
553595 Arc :: clone ( & logger) ,
554596 )
555- . expect ( "Persistence failed" ) ;
597+ . map_err ( |_| BuildError :: IOWriteFailed ) ? ;
556598 p2p_source
557599 }
558600 GossipSourceConfig :: RapidGossipSync ( rgs_server) => {
@@ -590,7 +632,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
590632
591633 let peer_manager = Arc :: new ( PeerManager :: new (
592634 msg_handler,
593- cur_time. as_secs ( ) . try_into ( ) . expect ( "System time error" ) ,
635+ cur_time. as_secs ( ) . try_into ( ) . map_err ( |_| BuildError :: InvalidSystemTime ) ? ,
594636 & ephemeral_bytes,
595637 Arc :: clone ( & logger) ,
596638 IgnoringMessageHandler { } ,
@@ -602,8 +644,8 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
602644 Ok ( payments) => {
603645 Arc :: new ( PaymentStore :: new ( payments, Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
604646 }
605- Err ( e ) => {
606- panic ! ( "Failed to read payment information: {}" , e . to_string ( ) ) ;
647+ Err ( _ ) => {
648+ return Err ( BuildError :: IOReadFailed ) ;
607649 }
608650 } ;
609651
@@ -614,7 +656,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
614656 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
615657 Arc :: new ( EventQueue :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
616658 } else {
617- panic ! ( "Failed to read event queue: {}" , e . to_string ( ) ) ;
659+ return Err ( BuildError :: IOReadFailed ) ;
618660 }
619661 }
620662 } ;
@@ -625,14 +667,14 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
625667 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
626668 Arc :: new ( PeerStore :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
627669 } else {
628- panic ! ( "Failed to read peer store: {}" , e . to_string ( ) ) ;
670+ return Err ( BuildError :: IOReadFailed ) ;
629671 }
630672 }
631673 } ;
632674
633675 let ( stop_sender, stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
634676
635- Node {
677+ Ok ( Node {
636678 runtime,
637679 stop_sender,
638680 stop_receiver,
@@ -651,5 +693,5 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
651693 scorer,
652694 peer_store,
653695 payment_store,
654- }
696+ } )
655697}
0 commit comments