@@ -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///
@@ -112,14 +149,14 @@ impl NodeBuilder {
112149 /// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
113150 ///
114151 /// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
115- pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) -> & mut Self {
152+ pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) -> Result < & mut Self , BuildError > {
116153 if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
117- panic ! ( "Failed to set seed due to invalid length." ) ;
154+ return Err ( BuildError :: InvalidSeedBytes ) ;
118155 }
119156 let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
120157 bytes. copy_from_slice ( & seed_bytes) ;
121158 self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
122- self
159+ Ok ( self )
123160 }
124161
125162 /// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -179,26 +216,28 @@ impl NodeBuilder {
179216
180217 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
181218 /// previously configured.
182- pub fn build ( & self ) -> Node < SqliteStore > {
219+ pub fn build ( & self ) -> Result < Node < SqliteStore > , BuildError > {
183220 let storage_dir_path = self . config . storage_dir_path . clone ( ) ;
184- fs:: create_dir_all ( storage_dir_path. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
221+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
222+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
185223 let kv_store = Arc :: new ( SqliteStore :: new ( storage_dir_path. into ( ) ) ) ;
186224 self . build_with_store ( kv_store)
187225 }
188226
189227 /// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
190228 /// previously configured.
191- pub fn build_with_fs_store ( & self ) -> Node < FilesystemStore > {
229+ pub fn build_with_fs_store ( & self ) -> Result < Node < FilesystemStore > , BuildError > {
192230 let storage_dir_path = self . config . storage_dir_path . clone ( ) ;
193- fs:: create_dir_all ( storage_dir_path. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
231+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
232+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
194233 let kv_store = Arc :: new ( FilesystemStore :: new ( storage_dir_path. into ( ) ) ) ;
195234 self . build_with_store ( kv_store)
196235 }
197236
198237 /// Builds a [`Node`] instance according to the options previously configured.
199238 pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
200239 & self , kv_store : Arc < K > ,
201- ) -> Node < K > {
240+ ) -> Result < Node < K > , BuildError > {
202241 let config = Arc :: new ( self . config . clone ( ) ) ;
203242
204243 let runtime = Arc :: new ( RwLock :: new ( None ) ) ;
@@ -251,8 +290,8 @@ impl ArcedNodeBuilder {
251290 /// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
252291 ///
253292 /// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
254- pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) {
255- self . inner . write ( ) . unwrap ( ) . set_entropy_seed_bytes ( seed_bytes) ;
293+ pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) -> Result < ( ) , BuildError > {
294+ self . inner . write ( ) . unwrap ( ) . set_entropy_seed_bytes ( seed_bytes) . map ( |_| ( ) )
256295 }
257296
258297 /// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -301,21 +340,21 @@ impl ArcedNodeBuilder {
301340
302341 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
303342 /// previously configured.
304- pub fn build ( & self ) -> Arc < Node < SqliteStore > > {
305- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build ( ) )
343+ pub fn build ( & self ) -> Result < Arc < Node < SqliteStore > > , BuildError > {
344+ self . inner . read ( ) . unwrap ( ) . build ( ) . map ( Arc :: new )
306345 }
307346
308347 /// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
309348 /// previously configured.
310- pub fn build_with_fs_store ( & self ) -> Arc < Node < FilesystemStore > > {
311- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) )
349+ pub fn build_with_fs_store ( & self ) -> Result < Arc < Node < FilesystemStore > > , BuildError > {
350+ self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) . map ( Arc :: new )
312351 }
313352
314353 /// Builds a [`Node`] instance according to the options previously configured.
315354 pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
316355 & self , kv_store : Arc < K > ,
317- ) -> Arc < Node < K > > {
318- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) )
356+ ) -> Result < Arc < Node < K > > , BuildError > {
357+ self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) . map ( Arc :: new )
319358 }
320359}
321360
@@ -325,12 +364,12 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
325364 chain_data_source_config : Option < & ChainDataSourceConfig > ,
326365 gossip_source_config : Option < & GossipSourceConfig > , kv_store : Arc < K > ,
327366 runtime : Arc < RwLock < Option < tokio:: runtime:: Runtime > > > ,
328- ) -> Node < K > {
367+ ) -> Result < Node < K > , BuildError > {
329368 let ldk_data_dir = format ! ( "{}/ldk" , config. storage_dir_path) ;
330- fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
369+ fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
331370
332371 let bdk_data_dir = format ! ( "{}/bdk" , config. storage_dir_path) ;
333- fs:: create_dir_all ( bdk_data_dir. clone ( ) ) . expect ( "Failed to create BDK data directory" ) ;
372+ fs:: create_dir_all ( bdk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
334373
335374 // Initialize the Logger
336375 let log_file_path = format ! (
@@ -358,15 +397,15 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
358397 } ;
359398
360399 let xprv = bitcoin:: util:: bip32:: ExtendedPrivKey :: new_master ( config. network , & seed_bytes)
361- . expect ( "Failed to read wallet master key" ) ;
400+ . map_err ( |_| BuildError :: InvalidSeedBytes ) ? ;
362401
363402 let wallet_name = bdk:: wallet:: wallet_name_from_descriptor (
364403 Bip84 ( xprv, bdk:: KeychainKind :: External ) ,
365404 Some ( Bip84 ( xprv, bdk:: KeychainKind :: Internal ) ) ,
366405 config. network ,
367406 & Secp256k1 :: new ( ) ,
368407 )
369- . expect ( "Failed to derive on-chain wallet name" ) ;
408+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
370409
371410 let database_path = format ! ( "{}/bdk_wallet_{}.sqlite" , config. storage_dir_path, wallet_name) ;
372411 let database = SqliteDatabase :: new ( database_path) ;
@@ -377,7 +416,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
377416 config. network ,
378417 database,
379418 )
380- . expect ( "Failed to set up on-chain wallet" ) ;
419+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
381420
382421 let ( blockchain, tx_sync) = match chain_data_source_config {
383422 Some ( ChainDataSourceConfig :: Esplora ( server_url) ) => {
@@ -413,7 +452,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
413452 // Initialize the KeysManager
414453 let cur_time = SystemTime :: now ( )
415454 . duration_since ( SystemTime :: UNIX_EPOCH )
416- . expect ( "System time error: Clock may have gone backwards" ) ;
455+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
417456 let ldk_seed_bytes: [ u8 ; 32 ] = xprv. private_key . secret_bytes ( ) ;
418457 let keys_manager = Arc :: new ( KeysManager :: new (
419458 & ldk_seed_bytes,
@@ -430,7 +469,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
430469 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
431470 Arc :: new ( NetworkGraph :: new ( config. network , Arc :: clone ( & logger) ) )
432471 } else {
433- panic ! ( "Failed to read network graph: {}" , e . to_string ( ) ) ;
472+ return Err ( BuildError :: IOReadFailed ) ;
434473 }
435474 }
436475 } ;
@@ -450,7 +489,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
450489 Arc :: clone ( & logger) ,
451490 ) ) )
452491 } else {
453- panic ! ( "Failed to read scorer: {}" , e . to_string ( ) ) ;
492+ return Err ( BuildError :: IOReadFailed ) ;
454493 }
455494 }
456495 } ;
@@ -474,7 +513,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
474513 Vec :: new ( )
475514 } else {
476515 log_error ! ( logger, "Failed to read channel monitors: {}" , e. to_string( ) ) ;
477- panic ! ( "Failed to read channel monitors: {}" , e . to_string ( ) ) ;
516+ return Err ( BuildError :: IOReadFailed ) ;
478517 }
479518 }
480519 } ;
@@ -507,8 +546,10 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
507546 channel_monitor_references,
508547 ) ;
509548 let ( _hash, channel_manager) =
510- <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args)
511- . expect ( "Failed to read channel manager from store" ) ;
549+ <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args) . map_err ( |e| {
550+ log_error ! ( logger, "Failed to read channel manager from KVStore: {}" , e) ;
551+ BuildError :: IOReadFailed
552+ } ) ?;
512553 channel_manager
513554 } else {
514555 // We're starting a fresh node.
@@ -553,7 +594,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
553594
554595 let cur_time = SystemTime :: now ( )
555596 . duration_since ( SystemTime :: UNIX_EPOCH )
556- . expect ( "System time error: Clock may have gone backwards" ) ;
597+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
557598
558599 // Initialize the GossipSource
559600 // Use the configured gossip source, if the user set one, otherwise default to P2PNetwork.
@@ -570,7 +611,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
570611 Arc :: clone ( & kv_store) ,
571612 Arc :: clone ( & logger) ,
572613 )
573- . expect ( "Persistence failed" ) ;
614+ . map_err ( |_| BuildError :: IOWriteFailed ) ? ;
574615 p2p_source
575616 }
576617 GossipSourceConfig :: RapidGossipSync ( rgs_server) => {
@@ -608,7 +649,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
608649
609650 let peer_manager = Arc :: new ( PeerManager :: new (
610651 msg_handler,
611- cur_time. as_secs ( ) . try_into ( ) . expect ( "System time error" ) ,
652+ cur_time. as_secs ( ) . try_into ( ) . map_err ( |_| BuildError :: InvalidSystemTime ) ? ,
612653 & ephemeral_bytes,
613654 Arc :: clone ( & logger) ,
614655 IgnoringMessageHandler { } ,
@@ -620,8 +661,8 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
620661 Ok ( payments) => {
621662 Arc :: new ( PaymentStore :: new ( payments, Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
622663 }
623- Err ( e ) => {
624- panic ! ( "Failed to read payment information: {}" , e . to_string ( ) ) ;
664+ Err ( _ ) => {
665+ return Err ( BuildError :: IOReadFailed ) ;
625666 }
626667 } ;
627668
@@ -632,7 +673,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
632673 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
633674 Arc :: new ( EventQueue :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
634675 } else {
635- panic ! ( "Failed to read event queue: {}" , e . to_string ( ) ) ;
676+ return Err ( BuildError :: IOReadFailed ) ;
636677 }
637678 }
638679 } ;
@@ -643,14 +684,14 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
643684 if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
644685 Arc :: new ( PeerStore :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
645686 } else {
646- panic ! ( "Failed to read peer store: {}" , e . to_string ( ) ) ;
687+ return Err ( BuildError :: IOReadFailed ) ;
647688 }
648689 }
649690 } ;
650691
651692 let ( stop_sender, stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
652693
653- Node {
694+ Ok ( Node {
654695 runtime,
655696 stop_sender,
656697 stop_receiver,
@@ -669,5 +710,5 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
669710 scorer,
670711 peer_store,
671712 payment_store,
672- }
713+ } )
673714}
0 commit comments