@@ -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,48 @@ 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., have invalid length.
76
+ InvalidSeedBytes ,
77
+ /// The given seed file is invalid, e.g., has invalid length, or could not be read.
78
+ InvalidSeedFile ,
79
+ /// The current system time is invalid, clocks might have gone backwards.
80
+ InvalidSystemTime ,
81
+ /// We failed to read data from the [`KVStore`].
82
+ ReadFailed ,
83
+ /// We failed to write data to the [`KVStore`].
84
+ WriteFailed ,
85
+ /// We failed to access the given `storage_dir_path`.
86
+ StoragePathAccessFailed ,
87
+ /// We failed to setup the onchain wallet.
88
+ WalletSetupFailed ,
89
+ /// We failed to setup the logger.
90
+ LoggerSetupFailed ,
91
+ }
92
+
93
+ impl fmt:: Display for BuildError {
94
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
95
+ match * self {
96
+ Self :: InvalidSeedBytes => write ! ( f, "Given seed bytes are invalid." ) ,
97
+ Self :: InvalidSeedFile => write ! ( f, "Given seed file is invalid or could not be read." ) ,
98
+ Self :: InvalidSystemTime => {
99
+ write ! ( f, "System time is invalid. Clocks might have gone back in time." )
100
+ }
101
+ Self :: ReadFailed => write ! ( f, "Failed to read from store." ) ,
102
+ Self :: WriteFailed => write ! ( f, "Failed to write to store." ) ,
103
+ Self :: StoragePathAccessFailed => write ! ( f, "Failed to access the given storage path." ) ,
104
+ Self :: WalletSetupFailed => write ! ( f, "Failed to setup onchain wallet." ) ,
105
+ Self :: LoggerSetupFailed => write ! ( f, "Failed to setup the logger." ) ,
106
+ }
107
+ }
108
+ }
109
+
110
+ impl std:: error:: Error for BuildError { }
111
+
69
112
/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
70
113
/// the getgo.
71
114
///
@@ -112,14 +155,14 @@ impl NodeBuilder {
112
155
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
113
156
///
114
157
/// **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 {
158
+ pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : Vec < u8 > ) -> Result < & mut Self , BuildError > {
116
159
if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
117
- panic ! ( "Failed to set seed due to invalid length." ) ;
160
+ return Err ( BuildError :: InvalidSeedBytes ) ;
118
161
}
119
162
let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
120
163
bytes. copy_from_slice ( & seed_bytes) ;
121
164
self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
122
- self
165
+ Ok ( self )
123
166
}
124
167
125
168
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -179,26 +222,28 @@ impl NodeBuilder {
179
222
180
223
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
181
224
/// previously configured.
182
- pub fn build ( & self ) -> Node < SqliteStore > {
225
+ pub fn build ( & self ) -> Result < Node < SqliteStore > , BuildError > {
183
226
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" ) ;
227
+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
228
+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
185
229
let kv_store = Arc :: new ( SqliteStore :: new ( storage_dir_path. into ( ) ) ) ;
186
230
self . build_with_store ( kv_store)
187
231
}
188
232
189
233
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
190
234
/// previously configured.
191
- pub fn build_with_fs_store ( & self ) -> Node < FilesystemStore > {
235
+ pub fn build_with_fs_store ( & self ) -> Result < Node < FilesystemStore > , BuildError > {
192
236
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" ) ;
237
+ fs:: create_dir_all ( storage_dir_path. clone ( ) )
238
+ . map_err ( |_| BuildError :: StoragePathAccessFailed ) ?;
194
239
let kv_store = Arc :: new ( FilesystemStore :: new ( storage_dir_path. into ( ) ) ) ;
195
240
self . build_with_store ( kv_store)
196
241
}
197
242
198
243
/// Builds a [`Node`] instance according to the options previously configured.
199
244
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
200
245
& self , kv_store : Arc < K > ,
201
- ) -> Node < K > {
246
+ ) -> Result < Node < K > , BuildError > {
202
247
let config = Arc :: new ( self . config . clone ( ) ) ;
203
248
204
249
let runtime = Arc :: new ( RwLock :: new ( None ) ) ;
@@ -251,8 +296,8 @@ impl ArcedNodeBuilder {
251
296
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
252
297
///
253
298
/// **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) ;
299
+ pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) -> Result < ( ) , BuildError > {
300
+ self . inner . write ( ) . unwrap ( ) . set_entropy_seed_bytes ( seed_bytes) . map ( |_| ( ) )
256
301
}
257
302
258
303
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -301,21 +346,21 @@ impl ArcedNodeBuilder {
301
346
302
347
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
303
348
/// previously configured.
304
- pub fn build ( & self ) -> Arc < Node < SqliteStore > > {
305
- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build ( ) )
349
+ pub fn build ( & self ) -> Result < Arc < Node < SqliteStore > > , BuildError > {
350
+ self . inner . read ( ) . unwrap ( ) . build ( ) . map ( Arc :: new )
306
351
}
307
352
308
353
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
309
354
/// previously configured.
310
- pub fn build_with_fs_store ( & self ) -> Arc < Node < FilesystemStore > > {
311
- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) )
355
+ pub fn build_with_fs_store ( & self ) -> Result < Arc < Node < FilesystemStore > > , BuildError > {
356
+ self . inner . read ( ) . unwrap ( ) . build_with_fs_store ( ) . map ( Arc :: new )
312
357
}
313
358
314
359
/// Builds a [`Node`] instance according to the options previously configured.
315
360
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
316
361
& self , kv_store : Arc < K > ,
317
- ) -> Arc < Node < K > > {
318
- Arc :: new ( self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) )
362
+ ) -> Result < Arc < Node < K > > , BuildError > {
363
+ self . inner . read ( ) . unwrap ( ) . build_with_store ( kv_store) . map ( Arc :: new )
319
364
}
320
365
}
321
366
@@ -325,26 +370,30 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
325
370
chain_data_source_config : Option < & ChainDataSourceConfig > ,
326
371
gossip_source_config : Option < & GossipSourceConfig > , kv_store : Arc < K > ,
327
372
runtime : Arc < RwLock < Option < tokio:: runtime:: Runtime > > > ,
328
- ) -> Node < K > {
373
+ ) -> Result < Node < K > , BuildError > {
329
374
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" ) ;
375
+ fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
331
376
332
377
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" ) ;
378
+ fs:: create_dir_all ( bdk_data_dir. clone ( ) ) . map_err ( |_| BuildError :: StoragePathAccessFailed ) ? ;
334
379
335
380
// Initialize the Logger
336
381
let log_file_path = format ! (
337
382
"{}/logs/ldk_node_{}.log" ,
338
383
config. storage_dir_path,
339
384
chrono:: offset:: Local :: now( ) . format( "%Y_%m_%d" )
340
385
) ;
341
- let logger = Arc :: new ( FilesystemLogger :: new ( log_file_path. clone ( ) , config. log_level ) ) ;
386
+ let logger = Arc :: new (
387
+ FilesystemLogger :: new ( log_file_path. clone ( ) , config. log_level )
388
+ . map_err ( |_| BuildError :: LoggerSetupFailed ) ?,
389
+ ) ;
342
390
343
391
// Initialize the on-chain wallet and chain access
344
392
let seed_bytes = match entropy_source_config {
345
393
Some ( EntropySourceConfig :: SeedBytes ( bytes) ) => bytes. clone ( ) ,
346
394
Some ( EntropySourceConfig :: SeedFile ( seed_path) ) => {
347
- io:: utils:: read_or_generate_seed_file ( seed_path)
395
+ io:: utils:: read_or_generate_seed_file ( seed_path, Arc :: clone ( & logger) )
396
+ . map_err ( |_| BuildError :: InvalidSeedFile ) ?
348
397
}
349
398
Some ( EntropySourceConfig :: Bip39Mnemonic { mnemonic, passphrase } ) => match passphrase {
350
399
Some ( passphrase) => mnemonic. to_seed ( passphrase) ,
@@ -353,20 +402,21 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
353
402
None => {
354
403
// Default to read or generate from the default location generate a seed file.
355
404
let seed_path = format ! ( "{}/keys_seed" , config. storage_dir_path) ;
356
- io:: utils:: read_or_generate_seed_file ( & seed_path)
405
+ io:: utils:: read_or_generate_seed_file ( & seed_path, Arc :: clone ( & logger) )
406
+ . map_err ( |_| BuildError :: InvalidSeedFile ) ?
357
407
}
358
408
} ;
359
409
360
410
let xprv = bitcoin:: util:: bip32:: ExtendedPrivKey :: new_master ( config. network , & seed_bytes)
361
- . expect ( "Failed to read wallet master key" ) ;
411
+ . map_err ( |_| BuildError :: InvalidSeedBytes ) ? ;
362
412
363
413
let wallet_name = bdk:: wallet:: wallet_name_from_descriptor (
364
414
Bip84 ( xprv, bdk:: KeychainKind :: External ) ,
365
415
Some ( Bip84 ( xprv, bdk:: KeychainKind :: Internal ) ) ,
366
416
config. network ,
367
417
& Secp256k1 :: new ( ) ,
368
418
)
369
- . expect ( "Failed to derive on-chain wallet name" ) ;
419
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
370
420
371
421
let database_path = format ! ( "{}/bdk_wallet_{}.sqlite" , config. storage_dir_path, wallet_name) ;
372
422
let database = SqliteDatabase :: new ( database_path) ;
@@ -377,7 +427,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
377
427
config. network ,
378
428
database,
379
429
)
380
- . expect ( "Failed to set up on-chain wallet" ) ;
430
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
381
431
382
432
let ( blockchain, tx_sync) = match chain_data_source_config {
383
433
Some ( ChainDataSourceConfig :: Esplora ( server_url) ) => {
@@ -413,13 +463,14 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
413
463
// Initialize the KeysManager
414
464
let cur_time = SystemTime :: now ( )
415
465
. duration_since ( SystemTime :: UNIX_EPOCH )
416
- . expect ( "System time error: Clock may have gone backwards" ) ;
466
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
417
467
let ldk_seed_bytes: [ u8 ; 32 ] = xprv. private_key . secret_bytes ( ) ;
418
468
let keys_manager = Arc :: new ( KeysManager :: new (
419
469
& ldk_seed_bytes,
420
470
cur_time. as_secs ( ) ,
421
471
cur_time. subsec_nanos ( ) ,
422
472
Arc :: clone ( & wallet) ,
473
+ Arc :: clone ( & logger) ,
423
474
) ) ;
424
475
425
476
// Initialize the network graph, scorer, and router
@@ -430,7 +481,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
430
481
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
431
482
Arc :: new ( NetworkGraph :: new ( config. network , Arc :: clone ( & logger) ) )
432
483
} else {
433
- panic ! ( "Failed to read network graph: {}" , e . to_string ( ) ) ;
484
+ return Err ( BuildError :: ReadFailed ) ;
434
485
}
435
486
}
436
487
} ;
@@ -450,7 +501,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
450
501
Arc :: clone ( & logger) ,
451
502
) ) )
452
503
} else {
453
- panic ! ( "Failed to read scorer: {}" , e . to_string ( ) ) ;
504
+ return Err ( BuildError :: ReadFailed ) ;
454
505
}
455
506
}
456
507
} ;
@@ -474,7 +525,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
474
525
Vec :: new ( )
475
526
} else {
476
527
log_error ! ( logger, "Failed to read channel monitors: {}" , e. to_string( ) ) ;
477
- panic ! ( "Failed to read channel monitors: {}" , e . to_string ( ) ) ;
528
+ return Err ( BuildError :: ReadFailed ) ;
478
529
}
479
530
}
480
531
} ;
@@ -507,8 +558,10 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
507
558
channel_monitor_references,
508
559
) ;
509
560
let ( _hash, channel_manager) =
510
- <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args)
511
- . expect ( "Failed to read channel manager from store" ) ;
561
+ <( BlockHash , ChannelManager < K > ) >:: read ( & mut reader, read_args) . map_err ( |e| {
562
+ log_error ! ( logger, "Failed to read channel manager from KVStore: {}" , e) ;
563
+ BuildError :: ReadFailed
564
+ } ) ?;
512
565
channel_manager
513
566
} else {
514
567
// We're starting a fresh node.
@@ -553,7 +606,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
553
606
554
607
let cur_time = SystemTime :: now ( )
555
608
. duration_since ( SystemTime :: UNIX_EPOCH )
556
- . expect ( "System time error: Clock may have gone backwards" ) ;
609
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
557
610
558
611
// Initialize the GossipSource
559
612
// Use the configured gossip source, if the user set one, otherwise default to P2PNetwork.
@@ -570,7 +623,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
570
623
Arc :: clone ( & kv_store) ,
571
624
Arc :: clone ( & logger) ,
572
625
)
573
- . expect ( "Persistence failed" ) ;
626
+ . map_err ( |_| BuildError :: WriteFailed ) ? ;
574
627
p2p_source
575
628
}
576
629
GossipSourceConfig :: RapidGossipSync ( rgs_server) => {
@@ -608,7 +661,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
608
661
609
662
let peer_manager = Arc :: new ( PeerManager :: new (
610
663
msg_handler,
611
- cur_time. as_secs ( ) . try_into ( ) . expect ( "System time error" ) ,
664
+ cur_time. as_secs ( ) . try_into ( ) . map_err ( |_| BuildError :: InvalidSystemTime ) ? ,
612
665
& ephemeral_bytes,
613
666
Arc :: clone ( & logger) ,
614
667
IgnoringMessageHandler { } ,
@@ -620,8 +673,8 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
620
673
Ok ( payments) => {
621
674
Arc :: new ( PaymentStore :: new ( payments, Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
622
675
}
623
- Err ( e ) => {
624
- panic ! ( "Failed to read payment information: {}" , e . to_string ( ) ) ;
676
+ Err ( _ ) => {
677
+ return Err ( BuildError :: ReadFailed ) ;
625
678
}
626
679
} ;
627
680
@@ -632,7 +685,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
632
685
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
633
686
Arc :: new ( EventQueue :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
634
687
} else {
635
- panic ! ( "Failed to read event queue: {}" , e . to_string ( ) ) ;
688
+ return Err ( BuildError :: ReadFailed ) ;
636
689
}
637
690
}
638
691
} ;
@@ -643,14 +696,14 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
643
696
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
644
697
Arc :: new ( PeerStore :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
645
698
} else {
646
- panic ! ( "Failed to read peer store: {}" , e . to_string ( ) ) ;
699
+ return Err ( BuildError :: ReadFailed ) ;
647
700
}
648
701
}
649
702
} ;
650
703
651
704
let ( stop_sender, stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
652
705
653
- Node {
706
+ Ok ( Node {
654
707
runtime,
655
708
stop_sender,
656
709
stop_receiver,
@@ -669,5 +722,5 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
669
722
scorer,
670
723
peer_store,
671
724
payment_store,
672
- }
725
+ } )
673
726
}
0 commit comments