Skip to content

Commit 8248e2e

Browse files
committed
Break builder pattern and expose setters via bindings
Unfortunately there is no good way of exposing the builder pattern via Uniffi bindings currenlty. We therefore resort to internal mutability and using setters on the `Builder` object.
1 parent e104c21 commit 8248e2e

File tree

4 files changed

+92
-62
lines changed

4 files changed

+92
-62
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ The primary abstraction of the library is the `Node`, which can be retrieved by
1111
use ldk_node::Builder;
1212
use ldk_node::lightning_invoice::Invoice;
1313
use ldk_node::bitcoin::secp256k1::PublicKey;
14+
use ldk_node::bitcoin::Network;
1415
use std::str::FromStr;
1516

1617
fn main() {
17-
let node = Builder::new()
18-
.set_network("testnet")
19-
.set_esplora_server_url("https://blockstream.info/testnet/api".to_string())
20-
.build();
18+
let mut builder = Builder::new();
19+
builder.set_network(Network::Testnet);
20+
builder.set_esplora_server_url("https://blockstream.info/testnet/api".to_string());
2121

22+
let node = builder.build();
2223
node.start().unwrap();
2324

2425
let _funding_address = node.new_funding_address();

bindings/ldk_node.udl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ interface Builder {
1313
constructor();
1414
[Name=from_config]
1515
constructor(Config config);
16+
void set_entropy_seed_path(string seed_path);
17+
void set_entropy_seed_bytes(sequence<u8> seed_bytes);
18+
void set_entropy_bip39_mnemonic(Mnemonic mnemonic, string? passphrase);
19+
void set_gossip_source_p2p();
20+
void set_gossip_source_rgs(string rgs_server_url);
21+
void set_storage_dir_path(string storage_dir_path);
22+
void set_esplora_server_url(string esplora_server_url);
23+
void set_network(Network network);
24+
void set_listening_address(SocketAddr listening_address);
1625
Node build();
1726
};
1827

@@ -183,3 +192,6 @@ typedef string UserChannelId;
183192

184193
[Custom]
185194
typedef string Network;
195+
196+
[Custom]
197+
typedef string Mnemonic;

src/lib.rs

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@
2929
//! use ldk_node::Builder;
3030
//! use ldk_node::lightning_invoice::Invoice;
3131
//! use ldk_node::bitcoin::secp256k1::PublicKey;
32+
//! use ldk_node::bitcoin::Network;
3233
//! use std::str::FromStr;
3334
//!
3435
//! 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());
3939
//!
40+
//! let node = builder.build();
4041
//! node.start().unwrap();
4142
//!
4243
//! let _funding_address = node.new_funding_address();
@@ -142,6 +143,8 @@ use bitcoin::hashes::Hash;
142143
use bitcoin::secp256k1::PublicKey;
143144
use bitcoin::Network;
144145

146+
use bip39::Mnemonic;
147+
145148
use bitcoin::{Address, BlockHash, OutPoint, Txid};
146149

147150
use rand::Rng;
@@ -150,7 +153,6 @@ use std::convert::TryInto;
150153
use std::default::Default;
151154
use std::fs;
152155
use std::net::SocketAddr;
153-
use std::str::FromStr;
154156
use std::sync::atomic::{AtomicBool, Ordering};
155157
use std::sync::{Arc, Mutex, RwLock};
156158
use std::time::{Duration, Instant, SystemTime};
@@ -204,7 +206,7 @@ impl Default for Config {
204206
enum EntropySourceConfig {
205207
SeedFile(String),
206208
SeedBytes([u8; WALLET_KEYS_SEED_LEN]),
207-
Bip39Mnemonic { mnemonic: bip39::Mnemonic, passphrase: Option<String> },
209+
Bip39Mnemonic { mnemonic: Mnemonic, passphrase: Option<String> },
208210
}
209211

210212
#[derive(Debug, Clone)]
@@ -215,106 +217,105 @@ enum GossipSourceConfig {
215217

216218
/// A builder for an [`Node`] instance, allowing to set some configuration and module choices from
217219
/// the getgo.
218-
#[derive(Debug, Clone)]
220+
#[derive(Debug)]
219221
pub struct Builder {
220-
config: Config,
221-
entropy_source_config: Option<EntropySourceConfig>,
222-
gossip_source_config: Option<GossipSourceConfig>,
222+
config: Mutex<Config>,
223+
entropy_source_config: Mutex<Option<EntropySourceConfig>>,
224+
gossip_source_config: Mutex<Option<GossipSourceConfig>>,
223225
}
224226

225227
impl Builder {
226228
/// Creates a new builder instance with the default configuration.
227229
pub fn new() -> Self {
228-
let config = Config::default();
229-
let entropy_source_config = None;
230-
let gossip_source_config = None;
230+
let config = Mutex::new(Config::default());
231+
let entropy_source_config = Mutex::new(None);
232+
let gossip_source_config = Mutex::new(None);
231233
Self { config, entropy_source_config, gossip_source_config }
232234
}
233235

234236
/// Creates a new builder instance from an [`Config`].
235237
pub fn from_config(config: Config) -> Self {
236-
let entropy_source_config = None;
237-
let gossip_source_config = None;
238+
let config = Mutex::new(config);
239+
let entropy_source_config = Mutex::new(None);
240+
let gossip_source_config = Mutex::new(None);
238241
Self { config, entropy_source_config, gossip_source_config }
239242
}
240243

241244
/// Configures the [`Node`] instance to source its wallet entropy from a seed file on disk.
242245
///
243246
/// If the given file does not exist a new random seed file will be generated and
244247
/// stored at the given location.
245-
pub fn set_entropy_seed_path(&mut self, seed_path: String) -> &mut Self {
246-
self.entropy_source_config = Some(EntropySourceConfig::SeedFile(seed_path));
247-
self
248+
pub fn set_entropy_seed_path(&self, seed_path: String) {
249+
*self.entropy_source_config.lock().unwrap() =
250+
Some(EntropySourceConfig::SeedFile(seed_path));
251+
}
252+
253+
/// Configures the [`Node`] instance to source its wallet entropy from the given 64 seed bytes.
254+
///
255+
/// **Note:** Panics if the length of the given `seed_bytes` differs from 64.
256+
pub fn set_entropy_seed_bytes(&self, seed_bytes: Vec<u8>) {
257+
if seed_bytes.len() != WALLET_KEYS_SEED_LEN {
258+
panic!("Failed to set seed due to invalid length.");
259+
}
260+
let mut bytes = [0u8; WALLET_KEYS_SEED_LEN];
261+
bytes.copy_from_slice(&seed_bytes);
262+
*self.entropy_source_config.lock().unwrap() = Some(EntropySourceConfig::SeedBytes(bytes));
248263
}
249264

250-
/// Configures the [`Node`] instance to source its wallet entropy from the given seed bytes.
251-
pub fn set_entropy_seed_bytes(&mut self, seed_bytes: [u8; WALLET_KEYS_SEED_LEN]) -> &mut Self {
252-
self.entropy_source_config = Some(EntropySourceConfig::SeedBytes(seed_bytes));
253-
self
265+
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
266+
///
267+
/// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
268+
pub fn set_entropy_bip39_mnemonic(&self, mnemonic: Mnemonic, passphrase: Option<String>) {
269+
*self.entropy_source_config.lock().unwrap() =
270+
Some(EntropySourceConfig::Bip39Mnemonic { mnemonic, passphrase });
254271
}
255272

256273
/// Configures the [`Node`] instance to source its gossip data from the Lightning peer-to-peer
257274
/// network.
258-
pub fn set_gossip_source_p2p(&mut self) -> &mut Self {
259-
self.gossip_source_config = Some(GossipSourceConfig::P2PNetwork);
260-
self
275+
pub fn set_gossip_source_p2p(&self) {
276+
*self.gossip_source_config.lock().unwrap() = Some(GossipSourceConfig::P2PNetwork);
261277
}
262278

263279
/// Configures the [`Node`] instance to source its gossip data from the given RapidGossipSync
264280
/// server.
265-
pub fn set_gossip_source_rgs(&mut self, rgs_server_url: String) -> &mut Self {
266-
self.gossip_source_config = Some(GossipSourceConfig::RapidGossipSync(rgs_server_url));
267-
self
268-
}
269-
270-
/// Configures the [`Node`] instance to source its wallet entropy from a [BIP 39] mnemonic.
271-
///
272-
/// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
273-
pub fn set_entropy_bip39_mnemonic(
274-
&mut self, mnemonic: bip39::Mnemonic, passphrase: Option<String>,
275-
) -> &mut Self {
276-
self.entropy_source_config =
277-
Some(EntropySourceConfig::Bip39Mnemonic { mnemonic, passphrase });
278-
self
281+
pub fn set_gossip_source_rgs(&self, rgs_server_url: String) {
282+
*self.gossip_source_config.lock().unwrap() =
283+
Some(GossipSourceConfig::RapidGossipSync(rgs_server_url));
279284
}
280285

281286
/// Sets the used storage directory path.
282287
///
283288
/// Default: `/tmp/ldk_node/`
284-
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
285-
self.config.storage_dir_path = storage_dir_path;
286-
self
289+
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
290+
let mut config = self.config.lock().unwrap();
291+
config.storage_dir_path = storage_dir_path;
287292
}
288293

289294
/// Sets the Esplora server URL.
290295
///
291296
/// Default: `https://blockstream.info/api`
292-
pub fn set_esplora_server_url(&mut self, esplora_server_url: String) -> &mut Self {
293-
self.config.esplora_server_url = esplora_server_url;
294-
self
297+
pub fn set_esplora_server_url(&self, esplora_server_url: String) {
298+
let mut config = self.config.lock().unwrap();
299+
config.esplora_server_url = esplora_server_url;
295300
}
296301

297302
/// Sets the Bitcoin network used.
298-
///
299-
/// Options: `mainnet`/`bitcoin`, `testnet`, `regtest`, `signet`
300-
///
301-
/// Default: `regtest`
302-
pub fn set_network(&mut self, network: &str) -> &mut Self {
303-
self.config.network = Network::from_str(network).unwrap_or(Network::Regtest);
304-
self
303+
pub fn set_network(&self, network: Network) {
304+
let mut config = self.config.lock().unwrap();
305+
config.network = network;
305306
}
306307

307308
/// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections.
308309
///
309310
/// Default: `0.0.0.0:9735`
310-
pub fn set_listening_address(&mut self, listening_address: SocketAddr) -> &mut Self {
311-
self.config.listening_address = Some(listening_address);
312-
self
311+
pub fn set_listening_address(&self, listening_address: SocketAddr) {
312+
let mut config = self.config.lock().unwrap();
313+
config.listening_address = Some(listening_address);
313314
}
314315

315316
/// Builds a [`Node`] instance according to the options previously configured.
316317
pub fn build(&self) -> Arc<Node> {
317-
let config = Arc::new(self.config.clone());
318+
let config = Arc::new(self.config.lock().unwrap().clone());
318319

319320
let ldk_data_dir = format!("{}/ldk", config.storage_dir_path);
320321
fs::create_dir_all(ldk_data_dir.clone()).expect("Failed to create LDK data directory");
@@ -327,7 +328,9 @@ impl Builder {
327328
let logger = Arc::new(FilesystemLogger::new(log_file_path));
328329

329330
// Initialize the on-chain wallet and chain access
330-
let seed_bytes = if let Some(entropy_source_config) = &self.entropy_source_config {
331+
let seed_bytes = if let Some(entropy_source_config) =
332+
&*self.entropy_source_config.lock().unwrap()
333+
{
331334
// Use the configured entropy source, if the user set one.
332335
match entropy_source_config {
333336
EntropySourceConfig::SeedBytes(bytes) => bytes.clone(),
@@ -534,8 +537,9 @@ impl Builder {
534537

535538
// Initialize the GossipSource
536539
// Use the configured gossip source, if the user set one, otherwise default to P2PNetwork.
540+
let gossip_source_config_lock = self.gossip_source_config.lock().unwrap();
537541
let gossip_source_config =
538-
self.gossip_source_config.as_ref().unwrap_or(&GossipSourceConfig::P2PNetwork);
542+
gossip_source_config_lock.as_ref().unwrap_or(&GossipSourceConfig::P2PNetwork);
539543

540544
let gossip_source = match gossip_source_config {
541545
GossipSourceConfig::P2PNetwork => {

src/types.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use bitcoin::hashes::Hash;
2424
use bitcoin::secp256k1::PublicKey;
2525
use bitcoin::{Address, Network, OutPoint, Txid};
2626

27+
use bip39::Mnemonic;
28+
2729
use std::convert::TryInto;
2830
use std::net::SocketAddr;
2931
use std::str::FromStr;
@@ -415,3 +417,14 @@ pub struct PeerDetails {
415417
/// Indicates whether or not the user is currently has an active connection with the peer.
416418
pub is_connected: bool,
417419
}
420+
421+
impl UniffiCustomTypeConverter for Mnemonic {
422+
type Builtin = String;
423+
fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
424+
Ok(Mnemonic::from_str(&val).unwrap())
425+
}
426+
427+
fn from_custom(obj: Self) -> Self::Builtin {
428+
obj.to_string()
429+
}
430+
}

0 commit comments

Comments
 (0)