Skip to content

Commit a5fa997

Browse files
committed
Unify Node API around Rust types
So far the interface sometimes took `String`s, `&str`s, or actual Rust types. Moreover we sometimes took the arguments by reference and sometimes not. In order to make the interface more uniform, we here take a step towards the Rust types and taking arguments by reference. Note that some of the affected parts are due to change in the future, e.g., once we transition to using upstream's `NetAddress` for peer addresses.
1 parent 1c0b501 commit a5fa997

File tree

5 files changed

+45
-92
lines changed

5 files changed

+45
-92
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The primary abstraction of the library is the `Node`, which can be retrieved by
1010
```rust
1111
use ldk_node::Builder;
1212
use ldk_node::lightning_invoice::Invoice;
13+
use ldk_node::bitcoin::secp256k1::PublicKey;
1314
use std::str::FromStr;
1415

1516
fn main() {
@@ -23,13 +24,15 @@ fn main() {
2324
let _funding_address = node.new_funding_address();
2425

2526
// .. fund address ..
26-
27+
2728
node.sync_wallets().unwrap();
2829

29-
node.connect_open_channel("NODE_ID@PEER_ADDR:PORT", 10000, false).unwrap();
30+
let node_id = PublicKey::from_str("NODE_ID").unwrap();
31+
let node_addr = "IP_ADDR:PORT".parse().unwrap();
32+
node.connect_open_channel(&node_id, &node_addr, 10000, false).unwrap();
3033

3134
let invoice = Invoice::from_str("INVOICE_STR").unwrap();
32-
node.send_payment(invoice).unwrap();
35+
node.send_payment(&invoice).unwrap();
3336

3437
node.stop().unwrap();
3538
}

src/lib.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
//! ```no_run
2929
//! use ldk_node::Builder;
3030
//! use ldk_node::lightning_invoice::Invoice;
31+
//! use ldk_node::bitcoin::secp256k1::PublicKey;
3132
//! use std::str::FromStr;
3233
//!
3334
//! fn main() {
@@ -44,10 +45,12 @@
4445
//!
4546
//! node.sync_wallets().unwrap();
4647
//!
47-
//! node.connect_open_channel("NODE_ID@PEER_ADDR:PORT", 10000, false).unwrap();
48+
//! let node_id = PublicKey::from_str("NODE_ID").unwrap();
49+
//! let node_addr = "IP_ADDR:PORT".parse().unwrap();
50+
//! node.connect_open_channel(&node_id, &node_addr, 10000, false).unwrap();
4851
//!
4952
//! let invoice = Invoice::from_str("INVOICE_STR").unwrap();
50-
//! node.send_payment(invoice).unwrap();
53+
//! node.send_payment(&invoice).unwrap();
5154
//!
5255
//! node.stop().unwrap();
5356
//! }
@@ -60,8 +63,8 @@
6063
//! [`send_payment`]: Node::send_payment
6164
//!
6265
#![deny(missing_docs)]
63-
#![deny(broken_intra_doc_links)]
64-
#![deny(private_intra_doc_links)]
66+
#![deny(rustdoc::broken_intra_doc_links)]
67+
#![deny(rustdoc::private_intra_doc_links)]
6568
#![allow(bare_trait_objects)]
6669
#![allow(ellipsis_inclusive_range_patterns)]
6770
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
@@ -133,7 +136,7 @@ use bitcoin::BlockHash;
133136

134137
use rand::Rng;
135138

136-
use std::convert::{TryFrom, TryInto};
139+
use std::convert::TryInto;
137140
use std::default::Default;
138141
use std::fs;
139142
use std::net::SocketAddr;
@@ -167,7 +170,7 @@ pub struct Config {
167170
/// The used Bitcoin network.
168171
pub network: bitcoin::Network,
169172
/// The IP address and TCP port the node will listen on.
170-
pub listening_address: Option<String>,
173+
pub listening_address: Option<SocketAddr>,
171174
/// The default CLTV expiry delta to be used for payments.
172175
pub default_cltv_expiry_delta: u32,
173176
}
@@ -178,7 +181,7 @@ impl Default for Config {
178181
storage_dir_path: "/tmp/ldk_node/".to_string(),
179182
esplora_server_url: "http://localhost:3002".to_string(),
180183
network: bitcoin::Network::Regtest,
181-
listening_address: Some("0.0.0.0:9735".to_string()),
184+
listening_address: Some("0.0.0.0:9735".parse().unwrap()),
182185
default_cltv_expiry_delta: 144,
183186
}
184187
}
@@ -262,9 +265,8 @@ impl Builder {
262265

263266
/// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections.
264267
///
265-
/// Format: `ADDR:PORT`
266268
/// Default: `0.0.0.0:9735`
267-
pub fn set_listening_address(&mut self, listening_address: String) -> &mut Self {
269+
pub fn set_listening_address(&mut self, listening_address: SocketAddr) -> &mut Self {
268270
self.config.listening_address = Some(listening_address);
269271
self
270272
}
@@ -821,8 +823,8 @@ impl Node {
821823
self.channel_manager.get_our_node_id()
822824
}
823825

824-
/// Returns our own listening address and port.
825-
pub fn listening_address(&self) -> Option<String> {
826+
/// Returns our own listening address.
827+
pub fn listening_address(&self) -> Option<SocketAddr> {
826828
self.config.listening_address.clone()
827829
}
828830

@@ -847,7 +849,8 @@ impl Node {
847849
///
848850
/// Returns a temporary channel id
849851
pub fn connect_open_channel(
850-
&self, node_pubkey_and_address: &str, channel_amount_sats: u64, announce_channel: bool,
852+
&self, pubkey: &PublicKey, address: &SocketAddr, channel_amount_sats: u64,
853+
announce_channel: bool,
851854
) -> Result<(), Error> {
852855
let runtime_lock = self.running.read().unwrap();
853856
if runtime_lock.is_none() {
@@ -862,7 +865,7 @@ impl Node {
862865
return Err(Error::InsufficientFunds);
863866
}
864867

865-
let peer_info = PeerInfo::try_from(node_pubkey_and_address.to_string())?;
868+
let peer_info = PeerInfo { pubkey: pubkey.clone(), address: address.clone() };
866869

867870
let con_peer_pubkey = peer_info.pubkey.clone();
868871
let con_peer_addr = peer_info.address.clone();
@@ -999,7 +1002,7 @@ impl Node {
9991002
}
10001003

10011004
/// Send a payement given an invoice.
1002-
pub fn send_payment(&self, invoice: Invoice) -> Result<PaymentHash, Error> {
1005+
pub fn send_payment(&self, invoice: &Invoice) -> Result<PaymentHash, Error> {
10031006
if self.running.read().unwrap().is_none() {
10041007
return Err(Error::NotRunning);
10051008
}
@@ -1055,7 +1058,7 @@ impl Node {
10551058
/// This can be used to pay a so-called "zero-amount" invoice, i.e., an invoice that leaves the
10561059
/// amount paid to be determined by the user.
10571060
pub fn send_payment_using_amount(
1058-
&self, invoice: Invoice, amount_msat: u64,
1061+
&self, invoice: &Invoice, amount_msat: u64,
10591062
) -> Result<PaymentHash, Error> {
10601063
if self.running.read().unwrap().is_none() {
10611064
return Err(Error::NotRunning);
@@ -1281,15 +1284,15 @@ async fn do_connect_peer(
12811284
pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
12821285
logger: Arc<FilesystemLogger>,
12831286
) -> Result<(), Error> {
1284-
log_info!(logger, "connecting to peer: {}@{}", pubkey, peer_addr);
1287+
log_info!(logger, "Connecting to peer: {}@{}", pubkey, peer_addr);
12851288
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
12861289
{
12871290
Some(connection_closed_future) => {
12881291
let mut connection_closed_future = Box::pin(connection_closed_future);
12891292
loop {
12901293
match futures::poll!(&mut connection_closed_future) {
12911294
std::task::Poll::Ready(_) => {
1292-
log_info!(logger, "peer connection closed: {}@{}", pubkey, peer_addr);
1295+
log_info!(logger, "Peer connection closed: {}@{}", pubkey, peer_addr);
12931296
return Err(Error::ConnectionFailed);
12941297
}
12951298
std::task::Poll::Pending => {}
@@ -1302,7 +1305,7 @@ async fn do_connect_peer(
13021305
}
13031306
}
13041307
None => {
1305-
log_error!(logger, "failed to connect to peer: {}@{}", pubkey, peer_addr);
1308+
log_error!(logger, "Failed to connect to peer: {}@{}", pubkey, peer_addr);
13061309
Err(Error::ConnectionFailed)
13071310
}
13081311
}

src/peer_store.rs

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::hex_utils;
21
use crate::io::{KVStore, PEER_INFO_PERSISTENCE_KEY, PEER_INFO_PERSISTENCE_NAMESPACE};
32
use crate::logger::{log_error, Logger};
43
use crate::Error;
@@ -8,8 +7,7 @@ use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
87
use bitcoin::secp256k1::PublicKey;
98

109
use std::collections::HashMap;
11-
use std::convert::TryFrom;
12-
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
10+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
1311
use std::ops::Deref;
1412
use std::sync::RwLock;
1513

@@ -195,28 +193,10 @@ impl Writeable for PeerInfo {
195193
}
196194
}
197195

198-
impl TryFrom<String> for PeerInfo {
199-
type Error = Error;
200-
201-
fn try_from(peer_pubkey_and_ip_addr: String) -> Result<Self, Self::Error> {
202-
if let Some((pubkey_str, peer_str)) = peer_pubkey_and_ip_addr.split_once('@') {
203-
if let Some(pubkey) = hex_utils::to_compressed_pubkey(pubkey_str) {
204-
if let Some(peer_addr) =
205-
peer_str.to_socket_addrs().ok().and_then(|mut r| r.next()).map(|pa| pa)
206-
{
207-
return Ok(PeerInfo { pubkey, address: peer_addr });
208-
}
209-
}
210-
}
211-
Err(Error::PeerInfoParseFailed)
212-
}
213-
}
214-
215196
#[cfg(test)]
216197
mod tests {
217198
use super::*;
218199
use crate::test::utils::{TestLogger, TestStore};
219-
use proptest::prelude::*;
220200
use std::str::FromStr;
221201
use std::sync::Arc;
222202

@@ -248,42 +228,4 @@ mod tests {
248228
assert_eq!(deser_peer_store.get_peer(&pubkey), Some(expected_peer_info));
249229
assert!(!store.get_and_clear_did_persist());
250230
}
251-
252-
#[test]
253-
fn peer_info_parsing() {
254-
let valid_peer_info_str =
255-
"0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993@127.0.0.1:9738"
256-
.to_string();
257-
258-
let pubkey = PublicKey::from_str(
259-
"0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993",
260-
)
261-
.unwrap();
262-
let address: SocketAddr = "127.0.0.1:9738".parse().unwrap();
263-
let expected_peer_info = PeerInfo { pubkey, address };
264-
265-
assert_eq!(Ok(expected_peer_info), PeerInfo::try_from(valid_peer_info_str));
266-
267-
let invalid_peer_info_str1 =
268-
"02-76607124-ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993@127.0.0.1:9738"
269-
.to_string();
270-
assert_eq!(Err(Error::PeerInfoParseFailed), PeerInfo::try_from(invalid_peer_info_str1));
271-
272-
let invalid_peer_info_str2 =
273-
"0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993@333.0.0.1:9738"
274-
.to_string();
275-
assert_eq!(Err(Error::PeerInfoParseFailed), PeerInfo::try_from(invalid_peer_info_str2));
276-
277-
let invalid_peer_info_str3 =
278-
"0276607124ebe6a6c9338517b6f485825b27c2dcc0b9fc2aa6a4c0df91194e5993@127.0.0.19738"
279-
.to_string();
280-
assert_eq!(Err(Error::PeerInfoParseFailed), PeerInfo::try_from(invalid_peer_info_str3));
281-
}
282-
283-
proptest! {
284-
#[test]
285-
fn peer_info_parsing_doesnt_crash(s in "\\PC*") {
286-
let _ = PeerInfo::try_from(s.to_string());
287-
}
288-
}
289231
}

src/test/functional_tests.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ fn channel_full_cycle() {
3333
assert_eq!(node_b.on_chain_balance().unwrap().get_spendable(), 100000);
3434

3535
println!("\nA -- connect_open_channel -> B");
36-
let node_b_addr = format!("{}@{}", node_b.node_id(), node_b.listening_address().unwrap());
37-
node_a.connect_open_channel(&node_b_addr, 50000, true).unwrap();
36+
node_a
37+
.connect_open_channel(&node_b.node_id(), &node_b.listening_address().unwrap(), 50000, true)
38+
.unwrap();
3839

3940
let funding_txo = loop {
4041
let details = node_a.list_channels();
@@ -76,7 +77,7 @@ fn channel_full_cycle() {
7677
let invoice = node_b.receive_payment(invoice_amount, &"asdf", 9217).unwrap();
7778

7879
println!("\nA send_payment");
79-
let payment_hash = node_a.send_payment(invoice.clone()).unwrap();
80+
let payment_hash = node_a.send_payment(&invoice).unwrap();
8081

8182
expect_event!(node_a, PaymentSuccessful);
8283
expect_event!(node_b, PaymentReceived);
@@ -88,7 +89,7 @@ fn channel_full_cycle() {
8889
assert_eq!(node_b.payment_info(&payment_hash).unwrap().amount_msat, Some(invoice_amount));
8990

9091
// Assert we fail duplicate outbound payments.
91-
assert_eq!(Err(Error::NonUniquePaymentHash), node_a.send_payment(invoice));
92+
assert_eq!(Err(Error::NonUniquePaymentHash), node_a.send_payment(&invoice));
9293

9394
// Test under-/overpayment
9495
let invoice_amount = 1000000;
@@ -97,12 +98,12 @@ fn channel_full_cycle() {
9798
let underpaid_amount = invoice_amount - 1;
9899
assert_eq!(
99100
Err(Error::InvalidAmount),
100-
node_a.send_payment_using_amount(invoice, underpaid_amount)
101+
node_a.send_payment_using_amount(&invoice, underpaid_amount)
101102
);
102103

103104
let invoice = node_b.receive_payment(invoice_amount, &"asdf", 9217).unwrap();
104105
let overpaid_amount = invoice_amount + 100;
105-
let payment_hash = node_a.send_payment_using_amount(invoice, overpaid_amount).unwrap();
106+
let payment_hash = node_a.send_payment_using_amount(&invoice, overpaid_amount).unwrap();
106107
expect_event!(node_a, PaymentSuccessful);
107108
let received_amount = match node_b.next_event() {
108109
ref e @ Event::PaymentReceived { amount_msat, .. } => {
@@ -125,9 +126,9 @@ fn channel_full_cycle() {
125126
// Test "zero-amount" invoice payment
126127
let variable_amount_invoice = node_b.receive_variable_amount_payment(&"asdf", 9217).unwrap();
127128
let determined_amount = 1234567;
128-
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(variable_amount_invoice.clone()));
129+
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(&variable_amount_invoice));
129130
let payment_hash =
130-
node_a.send_payment_using_amount(variable_amount_invoice, determined_amount).unwrap();
131+
node_a.send_payment_using_amount(&variable_amount_invoice, determined_amount).unwrap();
131132

132133
expect_event!(node_a, PaymentSuccessful);
133134
let received_amount = match node_b.next_event() {
@@ -195,10 +196,14 @@ fn channel_open_fails_when_funds_insufficient() {
195196
assert_eq!(node_b.on_chain_balance().unwrap().get_spendable(), 100000);
196197

197198
println!("\nA -- connect_open_channel -> B");
198-
let node_b_addr = format!("{}@{}", node_b.node_id(), node_b.listening_address().unwrap());
199199
assert_eq!(
200200
Err(Error::InsufficientFunds),
201-
node_a.connect_open_channel(&node_b_addr, 120000, true)
201+
node_a.connect_open_channel(
202+
&node_b.node_id(),
203+
&node_b.listening_address().unwrap(),
204+
120000,
205+
true
206+
)
202207
);
203208
}
204209

src/test/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ pub fn random_config(esplora_url: &str) -> Config {
291291

292292
let rand_port = random_port();
293293
println!("Setting random LDK listening port: {}", rand_port);
294-
let listening_address = format!("127.0.0.1:{}", rand_port);
295-
config.listening_address = Some(listening_address);
294+
let listening_address_str = format!("127.0.0.1:{}", rand_port);
295+
config.listening_address = Some(listening_address_str.parse().unwrap());
296296

297297
config
298298
}

0 commit comments

Comments
 (0)