Skip to content

Commit c926a77

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 8cdca11 commit c926a77

File tree

6 files changed

+47
-111
lines changed

6 files changed

+47
-111
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/hex_utils.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use bitcoin::secp256k1::PublicKey;
21
use std::fmt::Write;
32

43
pub fn to_vec(hex: &str) -> Option<Vec<u8>> {
@@ -30,17 +29,3 @@ pub fn to_string(value: &[u8]) -> String {
3029
}
3130
res
3231
}
33-
34-
pub fn to_compressed_pubkey(hex: &str) -> Option<PublicKey> {
35-
if hex.len() != 33 * 2 {
36-
return None;
37-
}
38-
let data = match to_vec(&hex[0..33 * 2]) {
39-
Some(bytes) => bytes,
40-
None => return None,
41-
};
42-
match PublicKey::from_slice(&data) {
43-
Ok(pk) => Some(pk),
44-
Err(_) => None,
45-
}
46-
}

src/lib.rs

Lines changed: 23 additions & 22 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
}
@@ -819,8 +821,8 @@ impl Node {
819821
self.channel_manager.get_our_node_id()
820822
}
821823

822-
/// Returns our own listening address and port.
823-
pub fn listening_address(&self) -> Option<String> {
824+
/// Returns our own listening address.
825+
pub fn listening_address(&self) -> Option<SocketAddr> {
824826
self.config.listening_address.clone()
825827
}
826828

@@ -845,7 +847,8 @@ impl Node {
845847
///
846848
/// Returns a temporary channel id
847849
pub fn connect_open_channel(
848-
&self, node_pubkey_and_address: &str, channel_amount_sats: u64, announce_channel: bool,
850+
&self, node_id: &PublicKey, address: &SocketAddr, channel_amount_sats: u64,
851+
announce_channel: bool,
849852
) -> Result<(), Error> {
850853
let runtime_lock = self.running.read().unwrap();
851854
if runtime_lock.is_none() {
@@ -860,7 +863,7 @@ impl Node {
860863
return Err(Error::InsufficientFunds);
861864
}
862865

863-
let peer_info = PeerInfo::try_from(node_pubkey_and_address.to_string())?;
866+
let peer_info = PeerInfo { pubkey: node_id.clone(), address: address.clone() };
864867

865868
let con_peer_pubkey = peer_info.pubkey.clone();
866869
let con_peer_addr = peer_info.address.clone();
@@ -997,7 +1000,7 @@ impl Node {
9971000
}
9981001

9991002
/// Send a payement given an invoice.
1000-
pub fn send_payment(&self, invoice: Invoice) -> Result<PaymentHash, Error> {
1003+
pub fn send_payment(&self, invoice: &Invoice) -> Result<PaymentHash, Error> {
10011004
if self.running.read().unwrap().is_none() {
10021005
return Err(Error::NotRunning);
10031006
}
@@ -1062,7 +1065,7 @@ impl Node {
10621065
/// This can be used to pay a so-called "zero-amount" invoice, i.e., an invoice that leaves the
10631066
/// amount paid to be determined by the user.
10641067
pub fn send_payment_using_amount(
1065-
&self, invoice: Invoice, amount_msat: u64,
1068+
&self, invoice: &Invoice, amount_msat: u64,
10661069
) -> Result<PaymentHash, Error> {
10671070
if self.running.read().unwrap().is_none() {
10681071
return Err(Error::NotRunning);
@@ -1155,20 +1158,18 @@ impl Node {
11551158

11561159
/// Send a spontaneous, aka. "keysend", payment
11571160
pub fn send_spontaneous_payment(
1158-
&self, amount_msat: u64, node_id: &str,
1161+
&self, amount_msat: u64, node_id: &PublicKey,
11591162
) -> Result<PaymentHash, Error> {
11601163
if self.running.read().unwrap().is_none() {
11611164
return Err(Error::NotRunning);
11621165
}
11631166

1164-
let pubkey = hex_utils::to_compressed_pubkey(node_id).ok_or(Error::PeerInfoParseFailed)?;
1165-
11661167
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
11671168
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
11681169

11691170
let route_params = RouteParameters {
11701171
payment_params: PaymentParameters::from_node_id(
1171-
pubkey,
1172+
*node_id,
11721173
self.config.default_cltv_expiry_delta,
11731174
),
11741175
final_value_msat: amount_msat,
@@ -1325,15 +1326,15 @@ async fn do_connect_peer(
13251326
pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
13261327
logger: Arc<FilesystemLogger>,
13271328
) -> Result<(), Error> {
1328-
log_info!(logger, "connecting to peer: {}@{}", pubkey, peer_addr);
1329+
log_info!(logger, "Connecting to peer: {}@{}", pubkey, peer_addr);
13291330
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
13301331
{
13311332
Some(connection_closed_future) => {
13321333
let mut connection_closed_future = Box::pin(connection_closed_future);
13331334
loop {
13341335
match futures::poll!(&mut connection_closed_future) {
13351336
std::task::Poll::Ready(_) => {
1336-
log_info!(logger, "peer connection closed: {}@{}", pubkey, peer_addr);
1337+
log_info!(logger, "Peer connection closed: {}@{}", pubkey, peer_addr);
13371338
return Err(Error::ConnectionFailed);
13381339
}
13391340
std::task::Poll::Pending => {}
@@ -1346,7 +1347,7 @@ async fn do_connect_peer(
13461347
}
13471348
}
13481349
None => {
1349-
log_error!(logger, "failed to connect to peer: {}@{}", pubkey, peer_addr);
1350+
log_error!(logger, "Failed to connect to peer: {}@{}", pubkey, peer_addr);
13501351
Err(Error::ConnectionFailed)
13511352
}
13521353
}

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::{
32
KVStore, TransactionalWrite, PEER_INFO_PERSISTENCE_KEY, PEER_INFO_PERSISTENCE_NAMESPACE,
43
};
@@ -10,8 +9,7 @@ use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
109
use bitcoin::secp256k1::PublicKey;
1110

1211
use std::collections::HashMap;
13-
use std::convert::TryFrom;
14-
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
12+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
1513
use std::ops::Deref;
1614
use std::sync::RwLock;
1715

@@ -196,28 +194,10 @@ impl Writeable for PeerInfo {
196194
}
197195
}
198196

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

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

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
let outbound_payments_a =
8283
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
@@ -104,7 +105,7 @@ fn channel_full_cycle() {
104105
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount));
105106

106107
// Assert we fail duplicate outbound payments.
107-
assert_eq!(Err(Error::NonUniquePaymentHash), node_a.send_payment(invoice));
108+
assert_eq!(Err(Error::NonUniquePaymentHash), node_a.send_payment(&invoice));
108109

109110
// Test under-/overpayment
110111
let invoice_amount = 1000000;
@@ -113,12 +114,12 @@ fn channel_full_cycle() {
113114
let underpaid_amount = invoice_amount - 1;
114115
assert_eq!(
115116
Err(Error::InvalidAmount),
116-
node_a.send_payment_using_amount(invoice, underpaid_amount)
117+
node_a.send_payment_using_amount(&invoice, underpaid_amount)
117118
);
118119

119120
let invoice = node_b.receive_payment(invoice_amount, &"asdf", 9217).unwrap();
120121
let overpaid_amount = invoice_amount + 100;
121-
let payment_hash = node_a.send_payment_using_amount(invoice, overpaid_amount).unwrap();
122+
let payment_hash = node_a.send_payment_using_amount(&invoice, overpaid_amount).unwrap();
122123
expect_event!(node_a, PaymentSuccessful);
123124
let received_amount = match node_b.next_event() {
124125
ref e @ Event::PaymentReceived { amount_msat, .. } => {
@@ -141,9 +142,9 @@ fn channel_full_cycle() {
141142
// Test "zero-amount" invoice payment
142143
let variable_amount_invoice = node_b.receive_variable_amount_payment(&"asdf", 9217).unwrap();
143144
let determined_amount = 1234567;
144-
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(variable_amount_invoice.clone()));
145+
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(&variable_amount_invoice));
145146
let payment_hash =
146-
node_a.send_payment_using_amount(variable_amount_invoice, determined_amount).unwrap();
147+
node_a.send_payment_using_amount(&variable_amount_invoice, determined_amount).unwrap();
147148

148149
expect_event!(node_a, PaymentSuccessful);
149150
let received_amount = match node_b.next_event() {
@@ -211,10 +212,14 @@ fn channel_open_fails_when_funds_insufficient() {
211212
assert_eq!(node_b.on_chain_balance().unwrap().get_spendable(), 100000);
212213

213214
println!("\nA -- connect_open_channel -> B");
214-
let node_b_addr = format!("{}@{}", node_b.node_id(), node_b.listening_address().unwrap());
215215
assert_eq!(
216216
Err(Error::InsufficientFunds),
217-
node_a.connect_open_channel(&node_b_addr, 120000, true)
217+
node_a.connect_open_channel(
218+
&node_b.node_id(),
219+
&node_b.listening_address().unwrap(),
220+
120000,
221+
true
222+
)
218223
);
219224
}
220225

src/test/utils.rs

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

295295
let rand_port = random_port();
296296
println!("Setting random LDK listening port: {}", rand_port);
297-
let listening_address = format!("127.0.0.1:{}", rand_port);
298-
config.listening_address = Some(listening_address);
297+
let listening_address_str = format!("127.0.0.1:{}", rand_port);
298+
config.listening_address = Some(listening_address_str.parse().unwrap());
299299

300300
config
301301
}

0 commit comments

Comments
 (0)