Skip to content

Commit a3d0cff

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 b124eca commit a3d0cff

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);
@@ -1150,20 +1153,18 @@ impl Node {
11501153

11511154
/// Send a spontaneous, aka. "keysend", payment
11521155
pub fn send_spontaneous_payment(
1153-
&self, amount_msat: u64, node_id: &str,
1156+
&self, amount_msat: u64, node_id: &PublicKey,
11541157
) -> Result<PaymentHash, Error> {
11551158
if self.running.read().unwrap().is_none() {
11561159
return Err(Error::NotRunning);
11571160
}
11581161

1159-
let pubkey = hex_utils::to_compressed_pubkey(node_id).ok_or(Error::PeerInfoParseFailed)?;
1160-
11611162
let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
11621163
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
11631164

11641165
let route_params = RouteParameters {
11651166
payment_params: PaymentParameters::from_node_id(
1166-
pubkey,
1167+
*node_id,
11671168
self.config.default_cltv_expiry_delta,
11681169
),
11691170
final_value_msat: amount_msat,
@@ -1322,15 +1323,15 @@ async fn do_connect_peer(
13221323
pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
13231324
logger: Arc<FilesystemLogger>,
13241325
) -> Result<(), Error> {
1325-
log_info!(logger, "connecting to peer: {}@{}", pubkey, peer_addr);
1326+
log_info!(logger, "Connecting to peer: {}@{}", pubkey, peer_addr);
13261327
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
13271328
{
13281329
Some(connection_closed_future) => {
13291330
let mut connection_closed_future = Box::pin(connection_closed_future);
13301331
loop {
13311332
match futures::poll!(&mut connection_closed_future) {
13321333
std::task::Poll::Ready(_) => {
1333-
log_info!(logger, "peer connection closed: {}@{}", pubkey, peer_addr);
1334+
log_info!(logger, "Peer connection closed: {}@{}", pubkey, peer_addr);
13341335
return Err(Error::ConnectionFailed);
13351336
}
13361337
std::task::Poll::Pending => {}
@@ -1343,7 +1344,7 @@ async fn do_connect_peer(
13431344
}
13441345
}
13451346
None => {
1346-
log_error!(logger, "failed to connect to peer: {}@{}", pubkey, peer_addr);
1347+
log_error!(logger, "Failed to connect to peer: {}@{}", pubkey, peer_addr);
13471348
Err(Error::ConnectionFailed)
13481349
}
13491350
}

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
@@ -32,8 +32,9 @@ fn channel_full_cycle() {
3232
assert_eq!(node_b.on_chain_balance().unwrap().get_spendable(), 100000);
3333

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

3839
expect_event!(node_a, ChannelPending);
3940

@@ -78,7 +79,7 @@ fn channel_full_cycle() {
7879
let invoice = node_b.receive_payment(invoice_amount, &"asdf", 9217).unwrap();
7980

8081
println!("\nA send_payment");
81-
let payment_hash = node_a.send_payment(invoice.clone()).unwrap();
82+
let payment_hash = node_a.send_payment(&invoice).unwrap();
8283

8384
let outbound_payments_a =
8485
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
@@ -106,7 +107,7 @@ fn channel_full_cycle() {
106107
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount));
107108

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

111112
// Test under-/overpayment
112113
let invoice_amount = 1000000;
@@ -115,12 +116,12 @@ fn channel_full_cycle() {
115116
let underpaid_amount = invoice_amount - 1;
116117
assert_eq!(
117118
Err(Error::InvalidAmount),
118-
node_a.send_payment_using_amount(invoice, underpaid_amount)
119+
node_a.send_payment_using_amount(&invoice, underpaid_amount)
119120
);
120121

121122
let invoice = node_b.receive_payment(invoice_amount, &"asdf", 9217).unwrap();
122123
let overpaid_amount = invoice_amount + 100;
123-
let payment_hash = node_a.send_payment_using_amount(invoice, overpaid_amount).unwrap();
124+
let payment_hash = node_a.send_payment_using_amount(&invoice, overpaid_amount).unwrap();
124125
expect_event!(node_a, PaymentSuccessful);
125126
let received_amount = match node_b.next_event() {
126127
ref e @ Event::PaymentReceived { amount_msat, .. } => {
@@ -143,9 +144,9 @@ fn channel_full_cycle() {
143144
// Test "zero-amount" invoice payment
144145
let variable_amount_invoice = node_b.receive_variable_amount_payment(&"asdf", 9217).unwrap();
145146
let determined_amount = 1234567;
146-
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(variable_amount_invoice.clone()));
147+
assert_eq!(Err(Error::InvalidInvoice), node_a.send_payment(&variable_amount_invoice));
147148
let payment_hash =
148-
node_a.send_payment_using_amount(variable_amount_invoice, determined_amount).unwrap();
149+
node_a.send_payment_using_amount(&variable_amount_invoice, determined_amount).unwrap();
149150

150151
expect_event!(node_a, PaymentSuccessful);
151152
let received_amount = match node_b.next_event() {
@@ -213,10 +214,14 @@ fn channel_open_fails_when_funds_insufficient() {
213214
assert_eq!(node_b.on_chain_balance().unwrap().get_spendable(), 100000);
214215

215216
println!("\nA -- connect_open_channel -> B");
216-
let node_b_addr = format!("{}@{}", node_b.node_id(), node_b.listening_address().unwrap());
217217
assert_eq!(
218218
Err(Error::InsufficientFunds),
219-
node_a.connect_open_channel(&node_b_addr, 120000, true)
219+
node_a.connect_open_channel(
220+
&node_b.node_id(),
221+
&node_b.listening_address().unwrap(),
222+
120000,
223+
true
224+
)
220225
);
221226
}
222227

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)