]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Help users support sending MPP keysend
authorAlec Chen <alecchendev@gmail.com>
Mon, 8 May 2023 22:51:19 +0000 (17:51 -0500)
committerAlec Chen <alecchendev@gmail.com>
Fri, 9 Jun 2023 16:26:58 +0000 (11:26 -0500)
When routing a keysend payment, the user may want to signal to the
router whether to find multi-path routes in the
`PaymentParameters::for_keysend` helper, without going through manual
construction. Since some implementations do not support MPP keysend, we
have the user make the choice here rather than making it the default.

Some implementations will reject keysend payments with payment secrets,
so this commit also adds docs to `RecipientOnionFields` to communicate
this to the user.

lightning/src/ln/channelmanager.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/outbound_payment.rs
lightning/src/routing/router.rs

index f6cb81376e2490a205127760d5d6f14f0798bf0c..9007188fdafe992ef5dc5eb39a77978b9c3e314d 100644 (file)
@@ -2924,8 +2924,6 @@ where
        /// Similar to regular payments, you MUST NOT reuse a `payment_preimage` value. See
        /// [`send_payment`] for more information about the risks of duplicate preimage usage.
        ///
-       /// Note that `route` must have exactly one path.
-       ///
        /// [`send_payment`]: Self::send_payment
        pub fn send_spontaneous_payment(&self, route: &Route, payment_preimage: Option<PaymentPreimage>, recipient_onion: RecipientOnionFields, payment_id: PaymentId) -> Result<PaymentHash, PaymentSendFailure> {
                let best_block_height = self.best_block.read().unwrap().height();
@@ -8580,7 +8578,7 @@ mod tests {
 
                // Next, attempt a keysend payment and make sure it fails.
                let route_params = RouteParameters {
-                       payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV),
+                       payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV, false),
                        final_value_msat: 100_000,
                };
                let route = find_route(
@@ -8673,7 +8671,7 @@ mod tests {
 
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
                let route_params = RouteParameters {
-                       payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
+                       payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
                        final_value_msat: 10_000,
                };
                let network_graph = nodes[0].network_graph.clone();
@@ -8717,7 +8715,7 @@ mod tests {
 
                let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
                let route_params = RouteParameters {
-                       payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
+                       payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
                        final_value_msat: 10_000,
                };
                let network_graph = nodes[0].network_graph.clone();
index 7d4b86f5acabf6ae81d5f0df9b13f3090fb11d29..d24d32ba0fa039dd9356621ec66839b2c59ffc28 100644 (file)
@@ -533,11 +533,17 @@ impl InvoiceFeatures {
        /// [`PaymentParameters::for_keysend`], thus omitting the need for payers to manually construct an
        /// `InvoiceFeatures` for [`find_route`].
        ///
+       /// MPP keysend is not widely supported yet, so we parameterize support to allow the user to
+       /// choose whether their router should find multi-part routes.
+       ///
        /// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
        /// [`find_route`]: crate::routing::router::find_route
-       pub(crate) fn for_keysend() -> InvoiceFeatures {
+       pub(crate) fn for_keysend(allow_mpp: bool) -> InvoiceFeatures {
                let mut res = InvoiceFeatures::empty();
                res.set_variable_length_onion_optional();
+               if allow_mpp {
+                       res.set_basic_mpp_optional();
+               }
                res
        }
 }
index 98fc4bd95b6d58f100ae09aaa32519e57237598c..1efca73d47829a6ca334cf1f328120c2defe5de2 100644 (file)
@@ -9478,7 +9478,7 @@ fn test_keysend_payments_to_public_node() {
        let payer_pubkey = nodes[0].node.get_our_node_id();
        let payee_pubkey = nodes[1].node.get_our_node_id();
        let route_params = RouteParameters {
-               payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
+               payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
                final_value_msat: 10000,
        };
        let scorer = test_utils::TestScorer::new();
@@ -9509,7 +9509,7 @@ fn test_keysend_payments_to_private_node() {
 
        let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
        let route_params = RouteParameters {
-               payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
+               payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
                final_value_msat: 10000,
        };
        let network_graph = nodes[0].network_graph.clone();
index f107f3b558395fe7ea9da8f8a8194f8f52a9f634..39d95e9b841b32e07a06fe1b658efc89c0c7d00d 100644 (file)
@@ -414,9 +414,9 @@ pub struct RecipientOnionFields {
        /// If you do not have one, the [`Route`] you pay over must not contain multiple paths as
        /// multi-path payments require a recipient-provided secret.
        ///
-       /// Note that for spontaneous payments most lightning nodes do not currently support MPP
-       /// receives, thus you should generally never be providing a secret here for spontaneous
-       /// payments.
+       /// Some implementations may reject spontaneous payments with payment secrets, so you may only
+       /// want to provide a secret for a spontaneous payment if MPP is needed and you know your
+       /// recipient will not reject it.
        pub payment_secret: Option<PaymentSecret>,
        /// The payment metadata serves a similar purpose as [`Self::payment_secret`] but is of
        /// arbitrary length. This gives recipients substantially more flexibility to receive
@@ -447,10 +447,13 @@ impl RecipientOnionFields {
        }
 
        /// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create
-       /// payable HTLCs except for spontaneous payments, i.e. this should generally only be used for
-       /// calls to [`ChannelManager::send_spontaneous_payment`].
+       /// payable HTLCs except for single-path spontaneous payments, i.e. this should generally
+       /// only be used for calls to [`ChannelManager::send_spontaneous_payment`]. If you are sending
+       /// a spontaneous MPP this will not work as all MPP require payment secrets; you may
+       /// instead want to use [`RecipientOnionFields::secret_only`].
        ///
        /// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment
+       /// [`RecipientOnionFields::secret_only`]: RecipientOnionFields::secret_only
        pub fn spontaneous_empty() -> Self {
                Self { payment_secret: None, payment_metadata: None }
        }
index b33e021ab4fc30357a1124885c45b076419aed61..da3b3d4eb1b0eb135858cd2dc9537c3c1c641a19 100644 (file)
@@ -621,8 +621,17 @@ impl PaymentParameters {
        ///
        /// The `final_cltv_expiry_delta` should match the expected final CLTV delta the recipient has
        /// provided.
-       pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32) -> Self {
-               Self::from_node_id(payee_pubkey, final_cltv_expiry_delta).with_bolt11_features(InvoiceFeatures::for_keysend()).expect("PaymentParameters::from_node_id should always initialize the payee as unblinded")
+       ///
+       /// Note that MPP keysend is not widely supported yet. The `allow_mpp` lets you choose
+       /// whether your router will be allowed to find a multi-part route for this payment. If you
+       /// set `allow_mpp` to true, you should ensure a payment secret is set on send, likely via
+       /// [`RecipientOnionFields::secret_only`].
+       ///
+       /// [`RecipientOnionFields::secret_only`]: crate::ln::channelmanager::RecipientOnionFields::secret_only
+       pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32, allow_mpp: bool) -> Self {
+               Self::from_node_id(payee_pubkey, final_cltv_expiry_delta)
+                       .with_bolt11_features(InvoiceFeatures::for_keysend(allow_mpp))
+                       .expect("PaymentParameters::from_node_id should always initialize the payee as unblinded")
        }
 
        /// Includes the payee's features. Errors if the parameters were initialized with blinded payment