use crate::disk;
use crate::hex_utils;
use crate::{
- ChannelManager, FilesystemLogger, HTLCStatus, InvoicePayer, MillisatAmount, PaymentInfo,
- PaymentInfoStorage, PeerManager,
+ ChannelManager, HTLCStatus, InvoicePayer, MillisatAmount, PaymentInfo, PaymentInfoStorage,
+ PeerManager,
};
+use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use bitcoin::network::constants::Network;
use bitcoin::secp256k1::key::PublicKey;
-use lightning::chain::keysinterface::{KeysInterface, KeysManager};
+use lightning::chain::keysinterface::{KeysInterface, KeysManager, Recipient};
use lightning::ln::msgs::NetAddress;
-use lightning::ln::PaymentHash;
-use lightning::routing::network_graph::NetworkGraph;
-use lightning::routing::router;
-use lightning::routing::router::{Payee, RouteParameters};
-use lightning::routing::scorer::Scorer;
+use lightning::ln::{PaymentHash, PaymentPreimage};
use lightning::util::config::{ChannelConfig, ChannelHandshakeLimits, UserConfig};
use lightning::util::events::EventHandler;
use lightning_invoice::payment::PaymentError;
use std::ops::Deref;
use std::path::Path;
use std::str::FromStr;
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::time::Duration;
pub(crate) struct LdkUserInfo {
let network: Network = match env::args().skip(arg_idx).next().as_ref().map(String::as_str) {
Some("testnet") => Network::Testnet,
Some("regtest") => Network::Regtest,
+ Some("signet") => Network::Signet,
Some(net) => {
- panic!("Unsupported network provided. Options are: `regtest`, `testnet`. Got {}", net);
+ panic!("Unsupported network provided. Options are: `regtest`, `testnet`, and `signet`. Got {}", net);
}
None => Network::Testnet,
};
pub(crate) async fn poll_for_user_input<E: EventHandler>(
invoice_payer: Arc<InvoicePayer<E>>, peer_manager: Arc<PeerManager>,
channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
- network_graph: Arc<NetworkGraph>, scorer: Arc<Mutex<Scorer>>,
inbound_payments: PaymentInfoStorage, outbound_payments: PaymentInfoStorage,
- ldk_data_dir: String, logger: Arc<FilesystemLogger>, network: Network,
+ ldk_data_dir: String, network: Network,
) {
println!("LDK startup successful. To view available commands: \"help\".");
println!("LDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
Some(amt) => amt,
None => {
println!("ERROR: keysend requires an amount in millisatoshis: `keysend <dest_pubkey> <amt_msat>`");
-
continue;
}
};
}
};
keysend(
+ &*invoice_payer,
dest_pubkey,
amt_msat,
- network_graph.clone(),
- channel_manager.clone(),
+ &*keys_manager,
outbound_payments.clone(),
- logger.clone(),
- scorer.clone(),
);
}
"getinvoice" => {
println!("SUCCESS: connected to peer {}", pubkey);
}
}
- "listchannels" => list_channels(channel_manager.clone()),
+ "listchannels" => list_channels(&channel_manager),
"listpayments" => {
list_payments(inbound_payments.clone(), outbound_payments.clone())
}
channel_id.copy_from_slice(&channel_id_vec.unwrap());
force_close_channel(channel_id, channel_manager.clone());
}
- "nodeinfo" => node_info(channel_manager.clone(), peer_manager.clone()),
+ "nodeinfo" => node_info(&channel_manager, &peer_manager),
"listpeers" => list_peers(peer_manager.clone()),
"signmessage" => {
- const MSG_STARTPOS: usize = "signmsg".len() + 1;
+ const MSG_STARTPOS: usize = "signmessage".len() + 1;
if line.as_bytes().len() <= MSG_STARTPOS {
println!("ERROR: signmsg requires a message");
continue;
"{:?}",
lightning::util::message_signing::sign(
&line.as_bytes()[MSG_STARTPOS..],
- &keys_manager.get_node_secret()
+ &keys_manager.get_node_secret(Recipient::Node).unwrap()
)
);
}
println!("signmessage <message>");
}
-fn node_info(channel_manager: Arc<ChannelManager>, peer_manager: Arc<PeerManager>) {
+fn node_info(channel_manager: &Arc<ChannelManager>, peer_manager: &Arc<PeerManager>) {
println!("\t{{");
println!("\t\t node_pubkey: {}", channel_manager.get_our_node_id());
let chans = channel_manager.list_channels();
println!("\t\t num_channels: {}", chans.len());
println!("\t\t num_usable_channels: {}", chans.iter().filter(|c| c.is_usable).count());
- let local_balance_msat = chans
- .iter()
- .map(|c| c.unspendable_punishment_reserve.unwrap_or(0) * 1000 + c.outbound_capacity_msat)
- .sum::<u64>();
+ let local_balance_msat = chans.iter().map(|c| c.balance_msat).sum::<u64>();
println!("\t\t local_balance_msat: {}", local_balance_msat);
println!("\t\t num_peers: {}", peer_manager.get_peer_node_ids().len());
println!("\t}},");
println!("\t}},");
}
-fn list_channels(channel_manager: Arc<ChannelManager>) {
+fn list_channels(channel_manager: &Arc<ChannelManager>) {
print!("[");
for chan_info in channel_manager.list_channels() {
println!("");
}
println!("\t\tis_confirmed_onchain: {},", chan_info.is_funding_locked);
println!("\t\tchannel_value_satoshis: {},", chan_info.channel_value_satoshis);
- println!(
- "\t\tlocal_balance_msat: {},",
- chan_info.outbound_capacity_msat
- + chan_info.unspendable_punishment_reserve.unwrap_or(0) * 1000
- );
+ println!("\t\tlocal_balance_msat: {},", chan_info.balance_msat);
if chan_info.is_usable {
println!("\t\tavailable_balance_for_send_msat: {},", chan_info.outbound_capacity_msat);
println!("\t\tavailable_balance_for_recv_msat: {},", chan_info.inbound_capacity_msat);
return Ok(());
}
}
+ let res = do_connect_peer(pubkey, peer_addr, peer_manager).await;
+ if res.is_err() {
+ println!("ERROR: failed to connect to peer");
+ }
+ res
+}
+
+pub(crate) async fn do_connect_peer(
+ pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
+) -> Result<(), ()> {
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, peer_addr).await
{
Some(connection_closed_future) => {
loop {
match futures::poll!(&mut connection_closed_future) {
std::task::Poll::Ready(_) => {
- println!("ERROR: Peer disconnected before we finished the handshake");
return Err(());
}
std::task::Poll::Pending => {}
}
// Avoid blocking the tokio context by sleeping a bit
match peer_manager.get_peer_node_ids().iter().find(|id| **id == pubkey) {
- Some(_) => break,
+ Some(_) => return Ok(()),
None => tokio::time::sleep(Duration::from_millis(10)).await,
}
}
}
- None => {
- println!("ERROR: failed to connect to peer");
- return Err(());
- }
+ None => Err(()),
}
- Ok(())
}
fn open_channel(
);
}
-fn keysend(
- payee_pubkey: PublicKey, amt_msat: u64, network_graph: Arc<NetworkGraph>,
- channel_manager: Arc<ChannelManager>, payment_storage: PaymentInfoStorage,
- logger: Arc<FilesystemLogger>, scorer: Arc<Mutex<Scorer>>,
+fn keysend<E: EventHandler, K: KeysInterface>(
+ invoice_payer: &InvoicePayer<E>, payee_pubkey: PublicKey, amt_msat: u64, keys: &K,
+ payment_storage: PaymentInfoStorage,
) {
- let first_hops = channel_manager.list_usable_channels();
- let payer_pubkey = channel_manager.get_our_node_id();
-
- let payee = Payee::for_keysend(payee_pubkey);
- let params = RouteParameters { payee, final_value_msat: amt_msat, final_cltv_expiry_delta: 40 };
-
- let route = match router::find_route(
- &payer_pubkey,
- ¶ms,
- &network_graph,
- Some(&first_hops.iter().collect::<Vec<_>>()),
- logger,
- &scorer.lock().unwrap(),
+ let payment_preimage = keys.get_secure_random_bytes();
+
+ let status = match invoice_payer.pay_pubkey(
+ payee_pubkey,
+ PaymentPreimage(payment_preimage),
+ amt_msat,
+ 40,
) {
- Ok(r) => r,
- Err(e) => {
+ Ok(_payment_id) => {
+ println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey);
+ print!("> ");
+ HTLCStatus::Pending
+ }
+ Err(PaymentError::Invoice(e)) => {
+ println!("ERROR: invalid payee: {}", e);
+ print!("> ");
+ return;
+ }
+ Err(PaymentError::Routing(e)) => {
println!("ERROR: failed to find route: {}", e.err);
+ print!("> ");
return;
}
+ Err(PaymentError::Sending(e)) => {
+ println!("ERROR: failed to send payment: {:?}", e);
+ print!("> ");
+ HTLCStatus::Failed
+ }
};
let mut payments = payment_storage.lock().unwrap();
- let payment_hash = channel_manager.send_spontaneous_payment(&route, None).unwrap().0;
payments.insert(
- payment_hash,
+ PaymentHash(Sha256::hash(&payment_preimage).into_inner()),
PaymentInfo {
preimage: None,
secret: None,
- status: HTLCStatus::Pending,
+ status,
amt_msat: MillisatAmount(Some(amt_msat)),
},
);
Network::Bitcoin => Currency::Bitcoin,
Network::Testnet => Currency::BitcoinTestnet,
Network::Regtest => Currency::Regtest,
- Network::Signet => panic!("Signet unsupported"),
+ Network::Signet => Currency::Signet,
};
let invoice = match utils::create_invoice_from_channelmanager(
&channel_manager,