29
29
//! use ldk_node::{Builder, NetAddress};
30
30
//! use ldk_node::lightning_invoice::Invoice;
31
31
//! use ldk_node::bitcoin::secp256k1::PublicKey;
32
+ //! use ldk_node::bitcoin::Network;
32
33
//! use std::str::FromStr;
33
34
//!
34
35
//! fn main() {
35
- //! let node = Builder::new()
36
- //! .set_network("testnet")
37
- //! .set_esplora_server_url("https://blockstream.info/testnet/api".to_string())
38
- //! .build();
36
+ //! let mut builder = Builder::new();
37
+ //! builder.set_network(Network::Testnet);
38
+ //! builder.set_esplora_server_url("https://blockstream.info/testnet/api".to_string());
39
39
//!
40
+ //! let node = builder.build();
40
41
//! node.start().unwrap();
41
42
//!
42
43
//! let _funding_address = node.new_funding_address();
@@ -144,6 +145,8 @@ use bitcoin::hashes::Hash;
144
145
use bitcoin:: secp256k1:: PublicKey ;
145
146
use bitcoin:: Network ;
146
147
148
+ use bip39:: Mnemonic ;
149
+
147
150
use bitcoin:: { Address , BlockHash , OutPoint , Txid } ;
148
151
149
152
use rand:: Rng ;
@@ -152,7 +155,6 @@ use std::convert::TryInto;
152
155
use std:: default:: Default ;
153
156
use std:: fs;
154
157
use std:: net:: ToSocketAddrs ;
155
- use std:: str:: FromStr ;
156
158
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
157
159
use std:: sync:: { Arc , Mutex , RwLock } ;
158
160
use std:: time:: { Duration , Instant , SystemTime } ;
@@ -212,7 +214,7 @@ impl Default for Config {
212
214
enum EntropySourceConfig {
213
215
SeedFile ( String ) ,
214
216
SeedBytes ( [ u8 ; WALLET_KEYS_SEED_LEN ] ) ,
215
- Bip39Mnemonic { mnemonic : bip39 :: Mnemonic , passphrase : Option < String > } ,
217
+ Bip39Mnemonic { mnemonic : Mnemonic , passphrase : Option < String > } ,
216
218
}
217
219
218
220
#[ derive( Debug , Clone ) ]
@@ -223,107 +225,107 @@ enum GossipSourceConfig {
223
225
224
226
/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
225
227
/// the getgo.
226
- #[ derive( Debug , Clone ) ]
228
+ #[ derive( Debug ) ]
227
229
pub struct Builder {
228
- config : Config ,
229
- entropy_source_config : Option < EntropySourceConfig > ,
230
- gossip_source_config : Option < GossipSourceConfig > ,
230
+ config : RwLock < Config > ,
231
+ entropy_source_config : RwLock < Option < EntropySourceConfig > > ,
232
+ gossip_source_config : RwLock < Option < GossipSourceConfig > > ,
231
233
}
232
234
233
235
impl Builder {
234
236
/// Creates a new builder instance with the default configuration.
235
237
pub fn new ( ) -> Self {
236
- let config = Config :: default ( ) ;
237
- let entropy_source_config = None ;
238
- let gossip_source_config = None ;
238
+ let config = RwLock :: new ( Config :: default ( ) ) ;
239
+ let entropy_source_config = RwLock :: new ( None ) ;
240
+ let gossip_source_config = RwLock :: new ( None ) ;
239
241
Self { config, entropy_source_config, gossip_source_config }
240
242
}
241
243
242
244
/// Creates a new builder instance from an [`Config`].
243
245
pub fn from_config ( config : Config ) -> Self {
244
- let entropy_source_config = None ;
245
- let gossip_source_config = None ;
246
+ let config = RwLock :: new ( config) ;
247
+ let entropy_source_config = RwLock :: new ( None ) ;
248
+ let gossip_source_config = RwLock :: new ( None ) ;
246
249
Self { config, entropy_source_config, gossip_source_config }
247
250
}
248
251
249
252
/// Configures the [`Node`] instance to source its wallet entropy from a seed file on disk.
250
253
///
251
254
/// If the given file does not exist a new random seed file will be generated and
252
255
/// stored at the given location.
253
- pub fn set_entropy_seed_path ( & mut self , seed_path : String ) -> & mut Self {
254
- self . entropy_source_config = Some ( EntropySourceConfig :: SeedFile ( seed_path) ) ;
255
- self
256
+ pub fn set_entropy_seed_path ( & self , seed_path : String ) {
257
+ * self . entropy_source_config . write ( ) . unwrap ( ) =
258
+ Some ( EntropySourceConfig :: SeedFile ( seed_path) ) ;
259
+ }
260
+
261
+ /// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
262
+ ///
263
+ /// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
264
+ pub fn set_entropy_seed_bytes ( & self , seed_bytes : Vec < u8 > ) {
265
+ if seed_bytes. len ( ) != WALLET_KEYS_SEED_LEN {
266
+ panic ! ( "Failed to set seed due to invalid length." ) ;
267
+ }
268
+ let mut bytes = [ 0u8 ; WALLET_KEYS_SEED_LEN ] ;
269
+ bytes. copy_from_slice ( & seed_bytes) ;
270
+ * self . entropy_source_config . write ( ) . unwrap ( ) = Some ( EntropySourceConfig :: SeedBytes ( bytes) ) ;
256
271
}
257
272
258
- /// Configures the [`Node`] instance to source its wallet entropy from the given seed bytes.
259
- pub fn set_entropy_seed_bytes ( & mut self , seed_bytes : [ u8 ; WALLET_KEYS_SEED_LEN ] ) -> & mut Self {
260
- self . entropy_source_config = Some ( EntropySourceConfig :: SeedBytes ( seed_bytes) ) ;
261
- self
273
+ /// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
274
+ ///
275
+ /// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
276
+ pub fn set_entropy_bip39_mnemonic ( & self , mnemonic : Mnemonic , passphrase : Option < String > ) {
277
+ * self . entropy_source_config . write ( ) . unwrap ( ) =
278
+ Some ( EntropySourceConfig :: Bip39Mnemonic { mnemonic, passphrase } ) ;
262
279
}
263
280
264
281
/// Configures the [`Node`] instance to source its gossip data from the Lightning peer-to-peer
265
282
/// network.
266
- pub fn set_gossip_source_p2p ( & mut self ) -> & mut Self {
267
- self . gossip_source_config = Some ( GossipSourceConfig :: P2PNetwork ) ;
268
- self
283
+ pub fn set_gossip_source_p2p ( & self ) {
284
+ * self . gossip_source_config . write ( ) . unwrap ( ) = Some ( GossipSourceConfig :: P2PNetwork ) ;
269
285
}
270
286
271
287
/// Configures the [`Node`] instance to source its gossip data from the given RapidGossipSync
272
288
/// server.
273
- pub fn set_gossip_source_rgs ( & mut self , rgs_server_url : String ) -> & mut Self {
274
- self . gossip_source_config = Some ( GossipSourceConfig :: RapidGossipSync ( rgs_server_url) ) ;
275
- self
276
- }
277
-
278
- /// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
279
- ///
280
- /// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
281
- pub fn set_entropy_bip39_mnemonic (
282
- & mut self , mnemonic : bip39:: Mnemonic , passphrase : Option < String > ,
283
- ) -> & mut Self {
284
- self . entropy_source_config =
285
- Some ( EntropySourceConfig :: Bip39Mnemonic { mnemonic, passphrase } ) ;
286
- self
289
+ pub fn set_gossip_source_rgs ( & self , rgs_server_url : String ) {
290
+ * self . gossip_source_config . write ( ) . unwrap ( ) =
291
+ Some ( GossipSourceConfig :: RapidGossipSync ( rgs_server_url) ) ;
287
292
}
288
293
289
294
/// Sets the used storage directory path.
290
295
///
291
296
/// Default: `/tmp/ldk_node/`
292
- pub fn set_storage_dir_path ( & mut self , storage_dir_path : String ) -> & mut Self {
293
- self . config . storage_dir_path = storage_dir_path ;
294
- self
297
+ pub fn set_storage_dir_path ( & self , storage_dir_path : String ) {
298
+ let mut config = self . config . write ( ) . unwrap ( ) ;
299
+ config . storage_dir_path = storage_dir_path ;
295
300
}
296
301
297
302
/// Sets the Esplora server URL.
298
303
///
299
304
/// Default: `https://blockstream.info/api`
300
- pub fn set_esplora_server_url ( & mut self , esplora_server_url : String ) -> & mut Self {
301
- self . config . esplora_server_url = esplora_server_url ;
302
- self
305
+ pub fn set_esplora_server_url ( & self , esplora_server_url : String ) {
306
+ let mut config = self . config . write ( ) . unwrap ( ) ;
307
+ config . esplora_server_url = esplora_server_url ;
303
308
}
304
309
305
310
/// Sets the Bitcoin network used.
306
- ///
307
- /// Options: `mainnet`/`bitcoin`, `testnet`, `regtest`, `signet`
308
- ///
309
- /// Default: `regtest`
310
- pub fn set_network ( & mut self , network : & str ) -> & mut Self {
311
- self . config . network = Network :: from_str ( network) . unwrap_or ( Network :: Regtest ) ;
312
- self
311
+ pub fn set_network ( & self , network : Network ) {
312
+ let mut config = self . config . write ( ) . unwrap ( ) ;
313
+ config. network = network;
313
314
}
314
315
315
316
/// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections.
316
317
///
317
318
/// Default: `0.0.0.0:9735`
318
- pub fn set_listening_address ( & mut self , listening_address : NetAddress ) -> & mut Self {
319
- self . config . listening_address = Some ( listening_address ) ;
320
- self
319
+ pub fn set_listening_address ( & self , listening_address : NetAddress ) {
320
+ let mut config = self . config . write ( ) . unwrap ( ) ;
321
+ config . listening_address = Some ( listening_address ) ;
321
322
}
322
323
323
324
/// Builds a [`Node`] instance with a [`FilesystemStore`] backend and according to the options
324
325
/// previously configured.
325
326
pub fn build ( & self ) -> Arc < Node < FilesystemStore > > {
326
- let ldk_data_dir = format ! ( "{}/ldk" , self . config. storage_dir_path) ;
327
+ let config = self . config . read ( ) . unwrap ( ) ;
328
+ let ldk_data_dir = format ! ( "{}/ldk" , config. storage_dir_path) ;
327
329
let kv_store = Arc :: new ( FilesystemStore :: new ( ldk_data_dir. clone ( ) . into ( ) ) ) ;
328
330
self . build_with_store ( kv_store)
329
331
}
@@ -332,7 +334,7 @@ impl Builder {
332
334
pub fn build_with_store < K : KVStore + Sync + Send + ' static > (
333
335
& self , kv_store : Arc < K > ,
334
336
) -> Arc < Node < K > > {
335
- let config = Arc :: new ( self . config . clone ( ) ) ;
337
+ let config = Arc :: new ( self . config . read ( ) . unwrap ( ) . clone ( ) ) ;
336
338
337
339
let ldk_data_dir = format ! ( "{}/ldk" , config. storage_dir_path) ;
338
340
fs:: create_dir_all ( ldk_data_dir. clone ( ) ) . expect ( "Failed to create LDK data directory" ) ;
@@ -345,7 +347,9 @@ impl Builder {
345
347
let logger = Arc :: new ( FilesystemLogger :: new ( log_file_path) ) ;
346
348
347
349
// Initialize the on-chain wallet and chain access
348
- let seed_bytes = if let Some ( entropy_source_config) = & self . entropy_source_config {
350
+ let seed_bytes = if let Some ( entropy_source_config) =
351
+ & * self . entropy_source_config . read ( ) . unwrap ( )
352
+ {
349
353
// Use the configured entropy source, if the user set one.
350
354
match entropy_source_config {
351
355
EntropySourceConfig :: SeedBytes ( bytes) => bytes. clone ( ) ,
@@ -550,8 +554,9 @@ impl Builder {
550
554
551
555
// Initialize the GossipSource
552
556
// Use the configured gossip source, if the user set one, otherwise default to P2PNetwork.
557
+ let gossip_source_config_lock = self . gossip_source_config . read ( ) . unwrap ( ) ;
553
558
let gossip_source_config =
554
- self . gossip_source_config . as_ref ( ) . unwrap_or ( & GossipSourceConfig :: P2PNetwork ) ;
559
+ gossip_source_config_lock . as_ref ( ) . unwrap_or ( & GossipSourceConfig :: P2PNetwork ) ;
555
560
556
561
let gossip_source = match gossip_source_config {
557
562
GossipSourceConfig :: P2PNetwork => {
0 commit comments