Skip to content

Unify interface types and expose connect / disconnect methods #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The primary abstraction of the library is the `Node`, which can be retrieved by
```rust
use ldk_node::Builder;
use ldk_node::lightning_invoice::Invoice;
use ldk_node::bitcoin::secp256k1::PublicKey;
use std::str::FromStr;

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

// .. fund address ..

node.sync_wallets().unwrap();

node.connect_open_channel("NODE_ID@PEER_ADDR:PORT", 10000, None, false).unwrap();
let node_id = PublicKey::from_str("NODE_ID").unwrap();
let node_addr = "IP_ADDR:PORT".parse().unwrap();
node.connect_open_channel(node_id, node_addr, 10000, None, false).unwrap();

let invoice = Invoice::from_str("INVOICE_STR").unwrap();
node.send_payment(invoice).unwrap();
node.send_payment(&invoice).unwrap();

node.stop().unwrap();
}
Expand Down
15 changes: 0 additions & 15 deletions src/hex_utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use bitcoin::secp256k1::PublicKey;
use std::fmt::Write;

pub fn to_vec(hex: &str) -> Option<Vec<u8>> {
Expand Down Expand Up @@ -30,17 +29,3 @@ pub fn to_string(value: &[u8]) -> String {
}
res
}

pub fn to_compressed_pubkey(hex: &str) -> Option<PublicKey> {
if hex.len() != 33 * 2 {
return None;
}
let data = match to_vec(&hex[0..33 * 2]) {
Some(bytes) => bytes,
None => return None,
};
match PublicKey::from_slice(&data) {
Ok(pk) => Some(pk),
Err(_) => None,
}
}
125 changes: 96 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
//! ```no_run
//! use ldk_node::Builder;
//! use ldk_node::lightning_invoice::Invoice;
//! use ldk_node::bitcoin::secp256k1::PublicKey;
//! use std::str::FromStr;
//!
//! fn main() {
Expand All @@ -44,10 +45,12 @@
//!
//! node.sync_wallets().unwrap();
//!
//! node.connect_open_channel("NODE_ID@PEER_ADDR:PORT", 10000, None, false).unwrap();
//! let node_id = PublicKey::from_str("NODE_ID").unwrap();
//! let node_addr = "IP_ADDR:PORT".parse().unwrap();
//! node.connect_open_channel(node_id, node_addr, 10000, None, false).unwrap();
//!
//! let invoice = Invoice::from_str("INVOICE_STR").unwrap();
//! node.send_payment(invoice).unwrap();
//! node.send_payment(&invoice).unwrap();
//!
//! node.stop().unwrap();
//! }
Expand All @@ -60,8 +63,8 @@
//! [`send_payment`]: Node::send_payment
//!
#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]
#![deny(private_intra_doc_links)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![allow(bare_trait_objects)]
#![allow(ellipsis_inclusive_range_patterns)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
Expand Down Expand Up @@ -100,9 +103,9 @@ use logger::{log_error, log_info, FilesystemLogger, Logger};

use lightning::chain::keysinterface::EntropySource;
use lightning::chain::{chainmonitor, BestBlock, Confirm, Watch};
use lightning::ln::channelmanager::{self, RecipientOnionFields};
use lightning::ln::channelmanager::{
ChainParameters, ChannelDetails, ChannelManagerReadArgs, PaymentId, Retry,
self, ChainParameters, ChannelDetails, ChannelManagerReadArgs, PaymentId, RecipientOnionFields,
Retry,
};
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler};
use lightning::ln::{PaymentHash, PaymentPreimage};
Expand Down Expand Up @@ -133,7 +136,7 @@ use bitcoin::BlockHash;

use rand::Rng;

use std::convert::{TryFrom, TryInto};
use std::convert::TryInto;
use std::default::Default;
use std::fs;
use std::net::SocketAddr;
Expand Down Expand Up @@ -167,7 +170,7 @@ pub struct Config {
/// The used Bitcoin network.
pub network: bitcoin::Network,
/// The IP address and TCP port the node will listen on.
pub listening_address: Option<String>,
pub listening_address: Option<SocketAddr>,
/// The default CLTV expiry delta to be used for payments.
pub default_cltv_expiry_delta: u32,
}
Expand All @@ -178,7 +181,7 @@ impl Default for Config {
storage_dir_path: "/tmp/ldk_node/".to_string(),
esplora_server_url: "http://localhost:3002".to_string(),
network: bitcoin::Network::Regtest,
listening_address: Some("0.0.0.0:9735".to_string()),
listening_address: Some("0.0.0.0:9735".parse().unwrap()),
default_cltv_expiry_delta: 144,
}
}
Expand Down Expand Up @@ -262,9 +265,8 @@ impl Builder {

/// Sets the IP address and TCP port on which [`Node`] will listen for incoming network connections.
///
/// Format: `ADDR:PORT`
/// Default: `0.0.0.0:9735`
pub fn set_listening_address(&mut self, listening_address: String) -> &mut Self {
pub fn set_listening_address(&mut self, listening_address: SocketAddr) -> &mut Self {
self.config.listening_address = Some(listening_address);
self
}
Expand Down Expand Up @@ -819,9 +821,9 @@ impl Node {
self.channel_manager.get_our_node_id()
}

/// Returns our own listening address and port.
pub fn listening_address(&self) -> Option<String> {
self.config.listening_address.clone()
/// Returns our own listening address.
pub fn listening_address(&self) -> Option<&SocketAddr> {
self.config.listening_address.as_ref()
}

/// Retrieve a new on-chain/funding address.
Expand All @@ -841,7 +843,74 @@ impl Node {
self.channel_manager.list_channels()
}

/// Connect to a node and opens a new channel.
/// Connect to a node on the peer-to-peer network.
///
/// If `permanently` is set to `true`, we'll remember the peer and reconnect to it on restart.
pub fn connect(
&self, node_id: PublicKey, address: SocketAddr, permanently: bool,
) -> Result<(), Error> {
let runtime_lock = self.running.read().unwrap();
if runtime_lock.is_none() {
return Err(Error::NotRunning);
}

let runtime = runtime_lock.as_ref().unwrap();

let peer_info = PeerInfo { pubkey: node_id, address };

let con_peer_pubkey = peer_info.pubkey;
let con_peer_addr = peer_info.address;
let con_success = Arc::new(AtomicBool::new(false));
let con_success_cloned = Arc::clone(&con_success);
let con_logger = Arc::clone(&self.logger);
let con_pm = Arc::clone(&self.peer_manager);

tokio::task::block_in_place(move || {
runtime.tokio_runtime.block_on(async move {
let res =
connect_peer_if_necessary(con_peer_pubkey, con_peer_addr, con_pm, con_logger)
.await;
con_success_cloned.store(res.is_ok(), Ordering::Release);
})
});

if !con_success.load(Ordering::Acquire) {
return Err(Error::ConnectionFailed);
}

log_info!(self.logger, "Connected to peer {}@{}. ", peer_info.pubkey, peer_info.address,);

if permanently {
self.peer_store.add_peer(peer_info)?;
}

Ok(())
}

/// Disconnects the peer with the given node id.
///
/// Will also remove the peer from the peer store, i.e., after this has been called we won't
/// try to reconnect on restart.
pub fn disconnect(&self, counterparty_node_id: &PublicKey) -> Result<(), Error> {
let runtime_lock = self.running.read().unwrap();
if runtime_lock.is_none() {
return Err(Error::NotRunning);
}

log_info!(self.logger, "Disconnecting peer {}..", counterparty_node_id);

match self.peer_store.remove_peer(&counterparty_node_id) {
Ok(()) => {}
Err(e) => {
log_error!(self.logger, "Failed to remove peer {}: {}", counterparty_node_id, e)
}
}

self.peer_manager.disconnect_by_node_id(*counterparty_node_id);
Ok(())
}

/// Connect to a node and open a new channel. Disconnects and re-connects are handled automatically
///
/// Disconnects and reconnects are handled automatically.
///
Expand All @@ -851,7 +920,7 @@ impl Node {
///
/// Returns a temporary channel id.
pub fn connect_open_channel(
&self, node_pubkey_and_address: &str, channel_amount_sats: u64,
&self, node_id: PublicKey, address: SocketAddr, channel_amount_sats: u64,
push_to_counterparty_msat: Option<u64>, announce_channel: bool,
) -> Result<(), Error> {
let runtime_lock = self.running.read().unwrap();
Expand All @@ -867,10 +936,10 @@ impl Node {
return Err(Error::InsufficientFunds);
}

let peer_info = PeerInfo::try_from(node_pubkey_and_address.to_string())?;
let peer_info = PeerInfo { pubkey: node_id, address };

let con_peer_pubkey = peer_info.pubkey.clone();
let con_peer_addr = peer_info.address.clone();
let con_peer_pubkey = peer_info.pubkey;
let con_peer_addr = peer_info.address;
let con_success = Arc::new(AtomicBool::new(false));
let con_success_cloned = Arc::clone(&con_success);
let con_logger = Arc::clone(&self.logger);
Expand Down Expand Up @@ -913,12 +982,12 @@ impl Node {
Some(user_config),
) {
Ok(_) => {
self.peer_store.add_peer(peer_info.clone())?;
log_info!(
self.logger,
"Initiated channel creation with peer {}. ",
peer_info.pubkey
);
self.peer_store.add_peer(peer_info)?;
Ok(())
}
Err(e) => {
Expand Down Expand Up @@ -1005,7 +1074,7 @@ impl Node {
}

/// Send a payement given an invoice.
pub fn send_payment(&self, invoice: Invoice) -> Result<PaymentHash, Error> {
pub fn send_payment(&self, invoice: &Invoice) -> Result<PaymentHash, Error> {
if self.running.read().unwrap().is_none() {
return Err(Error::NotRunning);
}
Expand Down Expand Up @@ -1070,7 +1139,7 @@ impl Node {
/// This can be used to pay a so-called "zero-amount" invoice, i.e., an invoice that leaves the
/// amount paid to be determined by the user.
pub fn send_payment_using_amount(
&self, invoice: Invoice, amount_msat: u64,
&self, invoice: &Invoice, amount_msat: u64,
) -> Result<PaymentHash, Error> {
if self.running.read().unwrap().is_none() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -1158,20 +1227,18 @@ impl Node {

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

let pubkey = hex_utils::to_compressed_pubkey(node_id).ok_or(Error::PeerInfoParseFailed)?;

let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes());
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());

let route_params = RouteParameters {
payment_params: PaymentParameters::from_node_id(
pubkey,
*node_id,
self.config.default_cltv_expiry_delta,
),
final_value_msat: amount_msat,
Expand Down Expand Up @@ -1330,15 +1397,15 @@ async fn do_connect_peer(
pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
logger: Arc<FilesystemLogger>,
) -> Result<(), Error> {
log_info!(logger, "connecting to peer: {}@{}", pubkey, peer_addr);
log_info!(logger, "Connecting to peer: {}@{}", pubkey, peer_addr);
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
{
Some(connection_closed_future) => {
let mut connection_closed_future = Box::pin(connection_closed_future);
loop {
match futures::poll!(&mut connection_closed_future) {
std::task::Poll::Ready(_) => {
log_info!(logger, "peer connection closed: {}@{}", pubkey, peer_addr);
log_info!(logger, "Peer connection closed: {}@{}", pubkey, peer_addr);
return Err(Error::ConnectionFailed);
}
std::task::Poll::Pending => {}
Expand All @@ -1351,7 +1418,7 @@ async fn do_connect_peer(
}
}
None => {
log_error!(logger, "failed to connect to peer: {}@{}", pubkey, peer_addr);
log_error!(logger, "Failed to connect to peer: {}@{}", pubkey, peer_addr);
Err(Error::ConnectionFailed)
}
}
Expand Down
Loading