Include min_final_cltv when generating invoices
[ldk-sample] / src / cli.rs
index ca1b84fed66fbe6f64f3cf4d63ddc141c0978ace..0144c001022662d7da6890cda460b24b30edc243 100644 (file)
@@ -12,8 +12,9 @@ use bitcoin::secp256k1::Secp256k1;
 use lightning::chain;
 use lightning::ln::channelmanager::{PaymentHash, PaymentPreimage, PaymentSecret};
 use lightning::ln::features::InvoiceFeatures;
-use lightning::routing::network_graph::NetGraphMsgHandler;
+use lightning::routing::network_graph::{NetGraphMsgHandler, RoutingFees};
 use lightning::routing::router;
+use lightning::routing::router::RouteHint;
 use lightning::util::config::UserConfig;
 use rand;
 use rand::Rng;
@@ -26,7 +27,6 @@ use std::path::Path;
 use std::str::FromStr;
 use std::sync::Arc;
 use std::time::Duration;
-use tokio::runtime::Handle;
 use tokio::sync::mpsc;
 
 pub(crate) struct LdkUserInfo {
@@ -98,11 +98,11 @@ pub(crate) fn parse_startup_args() -> Result<LdkUserInfo, ()> {
        })
 }
 
-pub(crate) fn poll_for_user_input(
+pub(crate) async fn poll_for_user_input(
        peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
        router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access>, Arc<FilesystemLogger>>>,
        payment_storage: PaymentInfoStorage, node_privkey: SecretKey, event_notifier: mpsc::Sender<()>,
-       ldk_data_dir: String, logger: Arc<FilesystemLogger>, runtime_handle: Handle, network: Network,
+       ldk_data_dir: String, logger: Arc<FilesystemLogger>, network: Network,
 ) {
        println!("LDK startup successful. To view available commands: \"help\".\nLDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
        let stdin = io::stdin();
@@ -149,7 +149,6 @@ pub(crate) fn poll_for_user_input(
                                                peer_addr,
                                                peer_manager.clone(),
                                                event_notifier.clone(),
-                                               runtime_handle.clone(),
                                        )
                                        .is_err()
                                        {
@@ -158,7 +157,6 @@ pub(crate) fn poll_for_user_input(
                                                continue;
                                        };
 
-                                       // let private_channel = match words.next().as_ref().map(String::as_str) {
                                        let announce_channel = match words.next() {
                                                Some("--public") | Some("--public=true") => true,
                                                Some("--public=false") => false,
@@ -203,6 +201,8 @@ pub(crate) fn poll_for_user_input(
                                                continue;
                                        }
                                        let invoice = invoice_res.unwrap();
+                                       let route_hints: Vec<lightning_invoice::Route> =
+                                               invoice.routes().iter().map(|&route| route.clone()).collect();
 
                                        let amt_pico_btc = invoice.amount_pico_btc();
                                        if amt_pico_btc.is_none() {
@@ -275,6 +275,7 @@ pub(crate) fn poll_for_user_input(
                                                payment_hash,
                                                payment_secret,
                                                invoice_features_opt,
+                                               route_hints,
                                                router.clone(),
                                                channel_manager.clone(),
                                                payment_storage.clone(),
@@ -328,7 +329,6 @@ pub(crate) fn poll_for_user_input(
                                                peer_addr,
                                                peer_manager.clone(),
                                                event_notifier.clone(),
-                                               runtime_handle.clone(),
                                        )
                                        .is_ok()
                                        {
@@ -448,7 +448,7 @@ fn list_payments(payment_storage: PaymentInfoStorage) {
 
 pub(crate) fn connect_peer_if_necessary(
        pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc<PeerManager>,
-       event_notifier: mpsc::Sender<()>, runtime: Handle,
+       event_notifier: mpsc::Sender<()>,
 ) -> Result<(), ()> {
        for node_pubkey in peer_manager.get_peer_node_ids() {
                if node_pubkey == pubkey {
@@ -459,7 +459,7 @@ pub(crate) fn connect_peer_if_necessary(
                Ok(stream) => {
                        let peer_mgr = peer_manager.clone();
                        let event_ntfns = event_notifier.clone();
-                       runtime.spawn(async move {
+                       tokio::spawn(async move {
                                lightning_net_tokio::setup_outbound(peer_mgr, event_ntfns, pubkey, stream).await;
                        });
                        let mut peer_connected = false;
@@ -504,6 +504,7 @@ fn open_channel(
 fn send_payment(
        payee: PublicKey, amt_msat: u64, final_cltv: u32, payment_hash: PaymentHash,
        payment_secret: Option<PaymentSecret>, payee_features: Option<InvoiceFeatures>,
+       mut route_hints: Vec<lightning_invoice::Route>,
        router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access>, Arc<FilesystemLogger>>>,
        channel_manager: Arc<ChannelManager>, payment_storage: PaymentInfoStorage,
        logger: Arc<FilesystemLogger>,
@@ -512,13 +513,29 @@ fn send_payment(
        let first_hops = channel_manager.list_usable_channels();
        let payer_pubkey = channel_manager.get_our_node_id();
 
+       let mut hints: Vec<RouteHint> = Vec::new();
+       for route in route_hints.drain(..) {
+               let route_hops = route.into_inner();
+               let last_hop = &route_hops[route_hops.len() - 1];
+               hints.push(RouteHint {
+                       src_node_id: last_hop.pubkey,
+                       short_channel_id: u64::from_be_bytes(last_hop.short_channel_id),
+                       fees: RoutingFees {
+                               base_msat: last_hop.fee_base_msat,
+                               proportional_millionths: last_hop.fee_proportional_millionths,
+                       },
+                       cltv_expiry_delta: last_hop.cltv_expiry_delta,
+                       htlc_minimum_msat: None,
+                       htlc_maximum_msat: None,
+               })
+       }
        let route = router::get_route(
                &payer_pubkey,
                &network_graph,
                &payee,
                payee_features,
                Some(&first_hops.iter().collect::<Vec<_>>()),
-               &vec![],
+               &hints.iter().collect::<Vec<_>>(),
                amt_msat,
                final_cltv,
                logger,
@@ -571,6 +588,7 @@ fn get_invoice(
 
        // Add route hints to the invoice.
        let our_channels = channel_manager.list_usable_channels();
+       let mut min_final_cltv_expiry = 9;
        for channel in our_channels {
                let short_channel_id = match channel.short_channel_id {
                        Some(id) => id.to_be_bytes(),
@@ -580,7 +598,9 @@ fn get_invoice(
                        Some(info) => info,
                        None => continue,
                };
-               println!("VMW: adding routehop, info.fee base: {}", forwarding_info.fee_base_msat);
+               if forwarding_info.cltv_expiry_delta > min_final_cltv_expiry {
+                       min_final_cltv_expiry = forwarding_info.cltv_expiry_delta;
+               }
                invoice = invoice.route(vec![lightning_invoice::RouteHop {
                        pubkey: channel.remote_network_id,
                        short_channel_id,
@@ -589,6 +609,7 @@ fn get_invoice(
                        cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
                }]);
        }
+       invoice = invoice.min_final_cltv_expiry(min_final_cltv_expiry.into());
 
        // Sign the invoice.
        let invoice =