@@ -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
///
@@ -112,14 +149,14 @@ impl NodeBuilder {
112
149
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
113
150
///
114
151
/// **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 > {
116
153
if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
117
- panic ! ( "Failed to set seed due to invalid length." ) ;
154
+ return Err ( BuildError :: InvalidSeedBytes ) ;
118
155
}
119
156
let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
120
157
bytes. copy_from_slice ( & seed_bytes) ;
121
158
self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
122
- self
159
+ Ok ( self )
123
160
}
124
161
125
162
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -179,26 +216,28 @@ impl NodeBuilder {
179
216
180
217
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
181
218
/// previously configured.
182
- pub fn build ( & self ) -> Node < SqliteStore > {
219
+ pub fn build ( & self ) -> Result < Node < SqliteStore > , BuildError > {
183
220
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 ) ?;
185
223
let kv_store = Arc :: new ( SqliteStore :: new ( storage_dir_path. into ( ) ) ) ;
186
224
self . build_with_store ( kv_store)
187
225
}
188
226
189
227
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
190
228
/// previously configured.
191
- pub fn build_with_fs_store ( & self ) -> Node < FilesystemStore > {
229
+ pub fn build_with_fs_store ( & self ) -> Result < Node < FilesystemStore > , BuildError > {
192
230
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 ) ?;
194
233
let kv_store = Arc :: new ( FilesystemStore :: new ( storage_dir_path. into ( ) ) ) ;
195
234
self . build_with_store ( kv_store)
196
235
}
197
236
198
237
/// Builds a [`Node`] instance according to the options previously configured.
199
238
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
200
239
& self , kv_store : Arc < K > ,
201
- ) -> Node < K > {
240
+ ) -> Result < Node < K > , BuildError > {
202
241
let config = Arc :: new ( self . config . clone ( ) ) ;
203
242
204
243
let runtime = Arc :: new ( RwLock :: new ( None ) ) ;
@@ -251,8 +290,8 @@ impl ArcedNodeBuilder {
251
290
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
252
291
///
253
292
/// **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 ( |_| ( ) )
256
295
}
257
296
258
297
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
@@ -301,21 +340,21 @@ impl ArcedNodeBuilder {
301
340
302
341
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
303
342
/// 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 )
306
345
}
307
346
308
347
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
309
348
/// 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 )
312
351
}
313
352
314
353
/// Builds a [`Node`] instance according to the options previously configured.
315
354
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
316
355
& 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 )
319
358
}
320
359
}
321
360
@@ -325,12 +364,12 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
325
364
chain_data_source_config : Option < & ChainDataSourceConfig > ,
326
365
gossip_source_config : Option < & GossipSourceConfig > , kv_store : Arc < K > ,
327
366
runtime : Arc < RwLock < Option < tokio:: runtime:: Runtime > > > ,
328
- ) -> Node < K > {
367
+ ) -> Result < Node < K > , BuildError > {
329
368
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 ) ? ;
331
370
332
371
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 ) ? ;
334
373
335
374
// Initialize the Logger
336
375
let log_file_path = format ! (
@@ -358,15 +397,15 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
358
397
} ;
359
398
360
399
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 ) ? ;
362
401
363
402
let wallet_name = bdk:: wallet:: wallet_name_from_descriptor (
364
403
Bip84 ( xprv, bdk:: KeychainKind :: External ) ,
365
404
Some ( Bip84 ( xprv, bdk:: KeychainKind :: Internal ) ) ,
366
405
config. network ,
367
406
& Secp256k1 :: new ( ) ,
368
407
)
369
- . expect ( "Failed to derive on-chain wallet name" ) ;
408
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
370
409
371
410
let database_path = format ! ( "{}/bdk_wallet_{}.sqlite" , config. storage_dir_path, wallet_name) ;
372
411
let database = SqliteDatabase :: new ( database_path) ;
@@ -377,7 +416,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
377
416
config. network ,
378
417
database,
379
418
)
380
- . expect ( "Failed to set up on-chain wallet" ) ;
419
+ . map_err ( |_| BuildError :: WalletSetupFailed ) ? ;
381
420
382
421
let ( blockchain, tx_sync) = match chain_data_source_config {
383
422
Some ( ChainDataSourceConfig :: Esplora ( server_url) ) => {
@@ -413,7 +452,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
413
452
// Initialize the KeysManager
414
453
let cur_time = SystemTime :: now ( )
415
454
. duration_since ( SystemTime :: UNIX_EPOCH )
416
- . expect ( "System time error: Clock may have gone backwards" ) ;
455
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
417
456
let ldk_seed_bytes: [ u8 ; 32 ] = xprv. private_key . secret_bytes ( ) ;
418
457
let keys_manager = Arc :: new ( KeysManager :: new (
419
458
& ldk_seed_bytes,
@@ -430,7 +469,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
430
469
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
431
470
Arc :: new ( NetworkGraph :: new ( config. network , Arc :: clone ( & logger) ) )
432
471
} else {
433
- panic ! ( "Failed to read network graph: {}" , e . to_string ( ) ) ;
472
+ return Err ( BuildError :: IOReadFailed ) ;
434
473
}
435
474
}
436
475
} ;
@@ -450,7 +489,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
450
489
Arc :: clone ( & logger) ,
451
490
) ) )
452
491
} else {
453
- panic ! ( "Failed to read scorer: {}" , e . to_string ( ) ) ;
492
+ return Err ( BuildError :: IOReadFailed ) ;
454
493
}
455
494
}
456
495
} ;
@@ -474,7 +513,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
474
513
Vec :: new ( )
475
514
} else {
476
515
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 ) ;
478
517
}
479
518
}
480
519
} ;
@@ -507,8 +546,10 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
507
546
channel_monitor_references,
508
547
) ;
509
548
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
+ } ) ?;
512
553
channel_manager
513
554
} else {
514
555
// We're starting a fresh node.
@@ -553,7 +594,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
553
594
554
595
let cur_time = SystemTime :: now ( )
555
596
. duration_since ( SystemTime :: UNIX_EPOCH )
556
- . expect ( "System time error: Clock may have gone backwards" ) ;
597
+ . map_err ( |_| BuildError :: InvalidSystemTime ) ? ;
557
598
558
599
// Initialize the GossipSource
559
600
// 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>(
570
611
Arc :: clone ( & kv_store) ,
571
612
Arc :: clone ( & logger) ,
572
613
)
573
- . expect ( "Persistence failed" ) ;
614
+ . map_err ( |_| BuildError :: IOWriteFailed ) ? ;
574
615
p2p_source
575
616
}
576
617
GossipSourceConfig :: RapidGossipSync ( rgs_server) => {
@@ -608,7 +649,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
608
649
609
650
let peer_manager = Arc :: new ( PeerManager :: new (
610
651
msg_handler,
611
- cur_time. as_secs ( ) . try_into ( ) . expect ( "System time error" ) ,
652
+ cur_time. as_secs ( ) . try_into ( ) . map_err ( |_| BuildError :: InvalidSystemTime ) ? ,
612
653
& ephemeral_bytes,
613
654
Arc :: clone ( & logger) ,
614
655
IgnoringMessageHandler { } ,
@@ -620,8 +661,8 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
620
661
Ok ( payments) => {
621
662
Arc :: new ( PaymentStore :: new ( payments, Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
622
663
}
623
- Err ( e ) => {
624
- panic ! ( "Failed to read payment information: {}" , e . to_string ( ) ) ;
664
+ Err ( _ ) => {
665
+ return Err ( BuildError :: IOReadFailed ) ;
625
666
}
626
667
} ;
627
668
@@ -632,7 +673,7 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
632
673
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
633
674
Arc :: new ( EventQueue :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
634
675
} else {
635
- panic ! ( "Failed to read event queue: {}" , e . to_string ( ) ) ;
676
+ return Err ( BuildError :: IOReadFailed ) ;
636
677
}
637
678
}
638
679
} ;
@@ -643,14 +684,14 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
643
684
if e. kind ( ) == std:: io:: ErrorKind :: NotFound {
644
685
Arc :: new ( PeerStore :: new ( Arc :: clone ( & kv_store) , Arc :: clone ( & logger) ) )
645
686
} else {
646
- panic ! ( "Failed to read peer store: {}" , e . to_string ( ) ) ;
687
+ return Err ( BuildError :: IOReadFailed ) ;
647
688
}
648
689
}
649
690
} ;
650
691
651
692
let ( stop_sender, stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
652
693
653
- Node {
694
+ Ok ( Node {
654
695
runtime,
655
696
stop_sender,
656
697
stop_receiver,
@@ -669,5 +710,5 @@ fn build_with_store_internal<K: KVStore + Sync + Send + 'static>(
669
710
scorer,
670
711
peer_store,
671
712
payment_store,
672
- }
713
+ } )
673
714
}
0 commit comments