Merge pull request #2035 from TheBlueMatt/2023-02-fix-no-con-discon
[rust-lightning] / lightning-invoice / src / utils.rs
index cee1a6b7a880d5fb34554e717a296c3fecdea848..868f0b297b1162da0551c8923b4ced23ab880ccb 100644 (file)
@@ -1,7 +1,6 @@
 //! Convenient utilities to create an invoice.
 
 use crate::{CreationError, Currency, Invoice, InvoiceBuilder, SignOrCreationError};
-use crate::payment::Payer;
 
 use crate::{prelude::*, Description, InvoiceDescription, Sha256};
 use bech32::ToBase32;
@@ -9,19 +8,17 @@ use bitcoin_hashes::Hash;
 use lightning::chain;
 use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
 use lightning::chain::keysinterface::{Recipient, NodeSigner, SignerProvider, EntropySource};
-use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
-use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY_DELTA};
-#[cfg(feature = "std")]
+use lightning::ln::{PaymentHash, PaymentSecret};
+use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, MIN_FINAL_CLTV_EXPIRY_DELTA};
 use lightning::ln::channelmanager::{PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA};
 use lightning::ln::inbound_payment::{create, create_from_hash, ExpandedKey};
 use lightning::routing::gossip::RoutingFees;
-use lightning::routing::router::{InFlightHtlcs, Route, RouteHint, RouteHintHop, Router};
+use lightning::routing::router::{RouteHint, RouteHintHop, Router};
 use lightning::util::logger::Logger;
 use secp256k1::PublicKey;
 use core::ops::Deref;
 use core::time::Duration;
 
-#[cfg(feature = "std")]
 /// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
 /// See [`PhantomKeysManager`] for more information on phantom node payments.
 ///
@@ -41,6 +38,8 @@ use core::time::Duration;
 ///
 /// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
 /// in excess of the current time.
+/// 
+/// `duration_since_epoch` is the current time since epoch in seconds.
 ///
 /// You can specify a custom `min_final_cltv_expiry_delta`, or let LDK default it to
 /// [`MIN_FINAL_CLTV_EXPIRY_DELTA`]. The provided expiry must be at least [`MIN_FINAL_CLTV_EXPIRY_DELTA`] - 3.
@@ -57,10 +56,13 @@ use core::time::Duration;
 /// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
 /// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
 /// [`MIN_FINAL_CLTV_EXPIRY_DETLA`]: lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA
+/// 
+/// This can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
+/// available and the current time is supplied by the caller.
 pub fn create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: String,
        invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
-       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>,
+       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
 ) -> Result<Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
@@ -71,11 +73,10 @@ where
        let description = InvoiceDescription::Direct(&description,);
        _create_phantom_invoice::<ES, NS, L>(
                amt_msat, payment_hash, description, invoice_expiry_delta_secs, phantom_route_hints,
-               entropy_source, node_signer, logger, network, min_final_cltv_expiry_delta,
+               entropy_source, node_signer, logger, network, min_final_cltv_expiry_delta, duration_since_epoch,
        )
 }
 
-#[cfg(feature = "std")]
 /// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
 /// See [`PhantomKeysManager`] for more information on phantom node payments.
 ///
@@ -97,6 +98,8 @@ where
 ///
 /// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for
 /// in excess of the current time.
+/// 
+/// `duration_since_epoch` is the current time since epoch in seconds.
 ///
 /// Note that the provided `keys_manager`'s `NodeSigner` implementation must support phantom
 /// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
@@ -107,10 +110,13 @@ where
 /// [`ChannelManager::create_inbound_payment`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment
 /// [`ChannelManager::create_inbound_payment_for_hash`]: lightning::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
 /// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
+/// 
+/// This can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
+/// available and the current time is supplied by the caller.
 pub fn create_phantom_invoice_with_description_hash<ES: Deref, NS: Deref, L: Deref>(
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, invoice_expiry_delta_secs: u32,
        description_hash: Sha256, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
-       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>,
+       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
 ) -> Result<Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
@@ -120,22 +126,20 @@ where
        _create_phantom_invoice::<ES, NS, L>(
                amt_msat, payment_hash, InvoiceDescription::Hash(&description_hash),
                invoice_expiry_delta_secs, phantom_route_hints, entropy_source, node_signer, logger, network,
-               min_final_cltv_expiry_delta,
+               min_final_cltv_expiry_delta, duration_since_epoch,
        )
 }
 
-#[cfg(feature = "std")]
 fn _create_phantom_invoice<ES: Deref, NS: Deref, L: Deref>(
        amt_msat: Option<u64>, payment_hash: Option<PaymentHash>, description: InvoiceDescription,
        invoice_expiry_delta_secs: u32, phantom_route_hints: Vec<PhantomRouteHints>, entropy_source: ES,
-       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>,
+       node_signer: NS, logger: L, network: Currency, min_final_cltv_expiry_delta: Option<u16>, duration_since_epoch: Duration,
 ) -> Result<Invoice, SignOrCreationError<()>>
 where
        ES::Target: EntropySource,
        NS::Target: NodeSigner,
        L::Target: Logger,
 {
-       use std::time::{SystemTime, UNIX_EPOCH};
 
        if phantom_route_hints.len() == 0 {
                return Err(SignOrCreationError::CreationError(
@@ -162,9 +166,7 @@ where
                        amt_msat,
                        payment_hash,
                        invoice_expiry_delta_secs,
-                       SystemTime::now()
-                               .duration_since(UNIX_EPOCH)
-                               .expect("Time must be > 1970")
+                       duration_since_epoch
                                .as_secs(),
                        min_final_cltv_expiry_delta,
                )
@@ -176,9 +178,7 @@ where
                        amt_msat,
                        invoice_expiry_delta_secs,
                        &entropy_source,
-                       SystemTime::now()
-                               .duration_since(UNIX_EPOCH)
-                               .expect("Time must be > 1970")
+                       duration_since_epoch
                                .as_secs(),
                        min_final_cltv_expiry_delta,
                )
@@ -189,7 +189,7 @@ where
                phantom_route_hints.len(), log_bytes!(payment_hash.0));
 
        let mut invoice = invoice
-               .current_timestamp()
+               .duration_since_epoch(duration_since_epoch)
                .payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
                .payment_secret(payment_secret)
                .min_final_cltv_expiry_delta(
@@ -633,51 +633,6 @@ fn filter_channels<L: Deref>(
                .collect::<Vec<RouteHint>>()
 }
 
-impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> Payer for ChannelManager<M, T, ES, NS, SP, F, R, L>
-where
-       M::Target: chain::Watch<<SP::Target as SignerProvider>::Signer>,
-       T::Target: BroadcasterInterface,
-       ES::Target: EntropySource,
-       NS::Target: NodeSigner,
-       SP::Target: SignerProvider,
-       F::Target: FeeEstimator,
-       R::Target: Router,
-       L::Target: Logger,
-{
-       fn node_id(&self) -> PublicKey {
-               self.get_our_node_id()
-       }
-
-       fn first_hops(&self) -> Vec<ChannelDetails> {
-               self.list_usable_channels()
-       }
-
-       fn send_payment(
-               &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>,
-               payment_id: PaymentId
-       ) -> Result<(), PaymentSendFailure> {
-               self.send_payment(route, payment_hash, payment_secret, payment_id)
-       }
-
-       fn send_spontaneous_payment(
-               &self, route: &Route, payment_preimage: PaymentPreimage, payment_id: PaymentId,
-       ) -> Result<(), PaymentSendFailure> {
-               self.send_spontaneous_payment(route, Some(payment_preimage), payment_id).map(|_| ())
-       }
-
-       fn retry_payment(
-               &self, route: &Route, payment_id: PaymentId
-       ) -> Result<(), PaymentSendFailure> {
-               self.retry_payment(route, payment_id)
-       }
-
-       fn abandon_payment(&self, payment_id: PaymentId) {
-               self.abandon_payment(payment_id)
-       }
-
-       fn inflight_htlcs(&self) -> InFlightHtlcs { self.compute_inflight_htlcs() }
-}
-
 #[cfg(test)]
 mod test {
        use core::time::Duration;
@@ -736,7 +691,7 @@ mod test {
                let first_hops = nodes[0].node.list_usable_channels();
                let network_graph = &node_cfgs[0].network_graph;
                let logger = test_utils::TestLogger::new();
-               let scorer = test_utils::TestScorer::with_penalty(0);
+               let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &route_params, &network_graph,
@@ -887,13 +842,13 @@ mod test {
 
                // With only one sufficient-value peer connected we should only get its hint
                scid_aliases.remove(&chan_b.0.short_channel_id_alias.unwrap());
-               nodes[0].node.peer_disconnected(&nodes[2].node.get_our_node_id(), false);
+               nodes[0].node.peer_disconnected(&nodes[2].node.get_our_node_id());
                match_invoice_routes(Some(1_000_000_000), &nodes[0], scid_aliases.clone());
 
                // If we don't have any sufficient-value peers connected we should get all hints with
                // sufficient value, even though there is a connected insufficient-value peer.
                scid_aliases.insert(chan_b.0.short_channel_id_alias.unwrap());
-               nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
+               nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
                match_invoice_routes(Some(1_000_000_000), &nodes[0], scid_aliases);
        }
 
@@ -1073,7 +1028,7 @@ mod test {
                        crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestLogger>(
                                Some(payment_amt), payment_hash, "test".to_string(), non_default_invoice_expiry_secs,
                                route_hints, &nodes[1].keys_manager, &nodes[1].keys_manager, &nodes[1].logger,
-                               Currency::BitcoinTestnet, None,
+                               Currency::BitcoinTestnet, None, Duration::from_secs(1234567)
                        ).unwrap();
                let (payment_hash, payment_secret) = (PaymentHash(invoice.payment_hash().into_inner()), *invoice.payment_secret());
                let payment_preimage = if user_generated_pmt_hash {
@@ -1100,7 +1055,7 @@ mod test {
                let first_hops = nodes[0].node.list_usable_channels();
                let network_graph = &node_cfgs[0].network_graph;
                let logger = test_utils::TestLogger::new();
-               let scorer = test_utils::TestScorer::with_penalty(0);
+               let scorer = test_utils::TestScorer::new();
                let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
                let route = find_route(
                        &nodes[0].node.get_our_node_id(), &params, &network_graph,
@@ -1184,7 +1139,7 @@ mod test {
                let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
                        &test_utils::TestKeysInterface, &test_utils::TestLogger>(Some(payment_amt), Some(payment_hash),
                                "test".to_string(), 3600, route_hints, &nodes[1].keys_manager, &nodes[1].keys_manager,
-                               &nodes[1].logger, Currency::BitcoinTestnet, None).unwrap();
+                               &nodes[1].logger, Currency::BitcoinTestnet, None, Duration::from_secs(1234567)).unwrap();
 
                let chan_0_1 = &nodes[1].node.list_usable_channels()[0];
                assert_eq!(invoice.route_hints()[0].0[0].htlc_minimum_msat, chan_0_1.inbound_htlc_minimum_msat);
@@ -1216,7 +1171,7 @@ mod test {
                >(
                        Some(payment_amt), None, non_default_invoice_expiry_secs, description_hash,
                        route_hints, &nodes[1].keys_manager, &nodes[1].keys_manager, &nodes[1].logger,
-                       Currency::BitcoinTestnet, None,
+                       Currency::BitcoinTestnet, None, Duration::from_secs(1234567),
                )
                .unwrap();
                assert_eq!(invoice.amount_pico_btc(), Some(200_000));
@@ -1242,10 +1197,11 @@ mod test {
                let payment_hash = Some(PaymentHash(Sha256::hash(&user_payment_preimage.0[..]).into_inner()));
                let non_default_invoice_expiry_secs = 4200;
                let min_final_cltv_expiry_delta = Some(100);
+               let duration_since_epoch = Duration::from_secs(1234567);
                let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
                        &test_utils::TestKeysInterface, &test_utils::TestLogger>(Some(payment_amt), payment_hash,
                                "".to_string(), non_default_invoice_expiry_secs, route_hints, &nodes[1].keys_manager, &nodes[1].keys_manager,
-                               &nodes[1].logger, Currency::BitcoinTestnet, min_final_cltv_expiry_delta).unwrap();
+                               &nodes[1].logger, Currency::BitcoinTestnet, min_final_cltv_expiry_delta, duration_since_epoch).unwrap();
                assert_eq!(invoice.amount_pico_btc(), Some(200_000));
                assert_eq!(invoice.min_final_cltv_expiry_delta(), (min_final_cltv_expiry_delta.unwrap() + 3) as u64);
                assert_eq!(invoice.expiry_time(), Duration::from_secs(non_default_invoice_expiry_secs.into()));
@@ -1559,7 +1515,7 @@ mod test {
                let invoice = crate::utils::create_phantom_invoice::<&test_utils::TestKeysInterface,
                        &test_utils::TestKeysInterface, &test_utils::TestLogger>(invoice_amt, None, "test".to_string(),
                                3600, phantom_route_hints, &invoice_node.keys_manager, &invoice_node.keys_manager,
-                               &invoice_node.logger, Currency::BitcoinTestnet, None).unwrap();
+                               &invoice_node.logger, Currency::BitcoinTestnet, None, Duration::from_secs(1234567)).unwrap();
 
                let invoice_hints = invoice.private_routes();