@@ -44,6 +44,7 @@ use bitcoin::BlockHash;
44
44
45
45
use std:: convert:: TryInto ;
46
46
use std:: default:: Default ;
47
+ use std:: fmt;
47
48
use std:: fs;
48
49
use std:: sync:: { Arc , Mutex , RwLock } ;
49
50
use std:: time:: SystemTime ;
@@ -66,6 +67,42 @@ enum GossipSourceConfig {
66
67
RapidGossipSync ( String ) ,
67
68
}
68
69
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
+
69
106
/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
70
107
/// the getgo.
71
108
///
@@ -111,13 +148,14 @@ impl NodeBuilder {
111
148
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
112
149
///
113
150
/// **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 > {
115
152
if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
116
- panic ! ( "Failed to set seed due to invalid length." ) ;
153
+ return Err ( BuildError :: InvalidSeedBytes ) ;
117
154
}
118
155
let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
119
156
bytes. copy_from_slice ( & seed_bytes) ;
120
157
self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
158
+ Ok ( ( ) )
121
159
}
122
160
123
161
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -167,26 +205,28 @@ impl NodeBuilder {
167
205
168
206
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
169
207
/// previously configured.
170
- pub fn build ( & self ) -> Node < SqliteStore > {
208
+ pub fn build ( & self ) -> Result < Node < SqliteStore > , BuildError > {
171
209
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 ) ?;
173
212
let kv_store = Arc :: new ( SqliteStore :: new ( storage_dir_path. into ( ) ) ) ;
174
213
self . build_with_store ( kv_store)
175
214
}
176
215
177
216
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
178
217
/// previously configured.
179
- pub fn build_with_fs_store ( & self ) -> Node < FilesystemStore > {
218
+ pub fn build_with_fs_store ( & self ) -> Result < Node < FilesystemStore > , BuildError > {
180
219
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 ) ?;
182
222
let kv_store = Arc :: new ( FilesystemStore :: new ( storage_dir_path. into ( ) ) ) ;
183
223
self . build_with_store ( kv_store)
184
224
}
185
225
186
226
/// Builds a [`Node`] instance according to the options previously configured.
187
227
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
188
228
& self , kv_store : Arc < K > ,
189
- ) -> Node < K > {
229
+ ) -> Result < Node < K > , BuildError > {
190
230
let config = Arc :: new ( self . config . clone ( ) ) ;
191
231
192
232
let runtime = Arc :: new ( RwLock :: new ( None ) ) ;
@@ -239,7 +279,7 @@ impl ArcedNodeBuilder {
239
279
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
240
280
///
241
281
/// **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 > {
243
283
self . inner . write ( ) . unwrap ( ) . set_entropy_seed_bytes ( seed_bytes)
244
284
}
245
285
@@ -289,21 +329,21 @@ impl ArcedNodeBuilder {
289
329
290
330
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
291
331
/// 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 )
294
334
}
295
335
296
336
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
297
337
/// 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 )
300
340
}
301
341
302
342
/// Builds a [`Node`] instance according to the options previously configured.
303
343
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
304
344
& 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 )
307
347
}
308
348
}
309
349
@@ -313,12 +353,12 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
313
353
chain_data_source_config : Option < & ' a ChainDataSourceConfig > ,
314
354
gossip_source_config : Option < & ' a GossipSourceConfig > , kv_store : Arc < K > ,
315
355
runtime : Arc < RwLock < Option < tokio:: runtime:: Runtime > > > ,
316
- ) -> Node < K > {
356
+ ) -> Result < Node < K > , BuildError > {
317
357
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 ) ? ;
319
359
320
360
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 ) ? ;
322
362
323
363
// Initialize the Logger
324
364
let log_file_path = format ! (
@@ -346,15 +386,15 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
346
386
} ;
347
387
348
388
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 ) ? ;
350
390
351
391
let wallet_name = bdk:: wallet:: wallet_name_from_descriptor (
352
392
Bip84 ( xprv, bdk:: KeychainKind :: External ) ,
353
393
Some ( Bip84 ( xprv, bdk:: KeychainKind :: Internal ) ) ,
354
394
config. network ,
355
395
& Secp256k1 :: new ( ) ,
356
396
)
357
- . expect ( "Failed to derive on-chain wallet name" ) ;
397
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
358
398
359
399
let database_path = format ! ( "{}/bdk_wallet_{}.sqlite" , config. storage_dir_path, wallet_name) ;
360
400
let database = SqliteDatabase :: new ( database_path) ;
@@ -365,7 +405,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
365
405
config. network ,
366
406
database,
367
407
)
368
- . expect ( "Failed to set up on-chain wallet" ) ;
408
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
369
409
370
410
let ( blockchain, tx_sync) = match chain_data_source_config {
371
411
Some ( ChainDataSourceConfig :: Esplora ( server_url) ) => {
@@ -401,7 +441,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
401
441
// Initialize the KeysManager
402
442
let cur_time = SystemTime :: now ( )
403
443
. duration_since ( SystemTime :: UNIX_EPOCH )
404
- . expect ( "System time error: Clock may have gone backwards" ) ;
444
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
405
445
let ldk_seed_bytes: [ u8 ; 32 ] = xprv. private_key . secret_bytes ( ) ;
406
446
let keys_manager = Arc :: new ( KeysManager :: new (
407
447
& ldk_seed_bytes,
@@ -418,7 +458,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
418
458
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
419
459
Arc :: new ( NetworkGraph :: new ( config. network , Arc :: clone ( & logger) ) )
420
460
} else {
421
- panic ! ( "Failed to read network graph: {}" , e . to_string ( ) ) ;
461
+ return Err ( BuildError :: IOReadFailed ) ;
422
462
}
423
463
}
424
464
} ;
@@ -438,7 +478,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
438
478
Arc :: clone ( & logger) ,
439
479
) ) )
440
480
} else {
441
- panic ! ( "Failed to read scorer: {}" , e . to_string ( ) ) ;
481
+ return Err ( BuildError :: IOReadFailed ) ;
442
482
}
443
483
}
444
484
} ;
@@ -462,7 +502,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
462
502
Vec :: new ( )
463
503
} else {
464
504
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 ) ;
466
506
}
467
507
}
468
508
} ;
@@ -489,8 +529,10 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
489
529
channel_monitor_references,
490
530
) ;
491
531
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
+ } ) ?;
494
536
channel_manager
495
537
} else {
496
538
// We're starting a fresh node.
@@ -535,7 +577,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
535
577
536
578
let cur_time = SystemTime :: now ( )
537
579
. duration_since ( SystemTime :: UNIX_EPOCH )
538
- . expect ( "System time error: Clock may have gone backwards" ) ;
580
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
539
581
540
582
// Initialize the GossipSource
541
583
// 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>(
552
594
Arc :: clone ( & kv_store) ,
553
595
Arc :: clone ( & logger) ,
554
596
)
555
- . expect ( "Persistence failed" ) ;
597
+ . map_err ( |_| BuildError :: IOWriteFailed ) ? ;
556
598
p2p_source
557
599
}
558
600
GossipSourceConfig :: RapidGossipSync ( rgs_server) => {
@@ -590,7 +632,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
590
632
591
633
let peer_manager = Arc :: new ( PeerManager :: new (
592
634
msg_handler,
593
- cur_time. as_secs ( ) . try_into ( ) . expect ( "System time error" ) ,
635
+ cur_time. as_secs ( ) . try_into ( ) . map_err ( |_| BuildError :: InvalidSystemTime ) ? ,
594
636
& ephemeral_bytes,
595
637
Arc :: clone ( & logger) ,
596
638
IgnoringMessageHandler { } ,
@@ -602,8 +644,8 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
602
644
Ok ( payments) => {
603
645
Arc :: new ( PaymentStore :: new ( payments, Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
604
646
}
605
- Err ( e ) => {
606
- panic ! ( "Failed to read payment information: {}" , e . to_string ( ) ) ;
647
+ Err ( _ ) => {
648
+ return Err ( BuildError :: IOReadFailed ) ;
607
649
}
608
650
} ;
609
651
@@ -614,7 +656,7 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
614
656
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
615
657
Arc :: new ( EventQueue :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
616
658
} else {
617
- panic ! ( "Failed to read event queue: {}" , e . to_string ( ) ) ;
659
+ return Err ( BuildError :: IOReadFailed ) ;
618
660
}
619
661
}
620
662
} ;
@@ -625,14 +667,14 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
625
667
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
626
668
Arc :: new ( PeerStore :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
627
669
} else {
628
- panic ! ( "Failed to read peer store: {}" , e . to_string ( ) ) ;
670
+ return Err ( BuildError :: IOReadFailed ) ;
629
671
}
630
672
}
631
673
} ;
632
674
633
675
let ( stop_sender, stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
634
676
635
- Node {
677
+ Ok ( Node {
636
678
runtime,
637
679
stop_sender,
638
680
stop_receiver,
@@ -651,5 +693,5 @@ fn build_with_store_internal<'a, K: KVStore + Sync + Send + 'static>(
651
693
scorer,
652
694
peer_store,
653
695
payment_store,
654
- }
696
+ } )
655
697
}
0 commit comments