Skip to content

Commit 42e2f1d

Browse files
authored
Merge pull request #2156 from alecchendev/2023-04-mpp-keysend
Support MPP Keysend
2 parents b6787a4 + 9db962c commit 42e2f1d

File tree

8 files changed

+346
-115
lines changed

8 files changed

+346
-115
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 131 additions & 101 deletions
Large diffs are not rendered by default.

lightning/src/ln/features.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,11 +535,17 @@ impl InvoiceFeatures {
535535
/// [`PaymentParameters::for_keysend`], thus omitting the need for payers to manually construct an
536536
/// `InvoiceFeatures` for [`find_route`].
537537
///
538+
/// MPP keysend is not widely supported yet, so we parameterize support to allow the user to
539+
/// choose whether their router should find multi-part routes.
540+
///
538541
/// [`PaymentParameters::for_keysend`]: crate::routing::router::PaymentParameters::for_keysend
539542
/// [`find_route`]: crate::routing::router::find_route
540-
pub(crate) fn for_keysend() -> InvoiceFeatures {
543+
pub(crate) fn for_keysend(allow_mpp: bool) -> InvoiceFeatures {
541544
let mut res = InvoiceFeatures::empty();
542545
res.set_variable_length_onion_optional();
546+
if allow_mpp {
547+
res.set_basic_mpp_optional();
548+
}
543549
res
544550
}
545551
}

lightning/src/ln/functional_test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2115,7 +2115,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_p
21152115
},
21162116
PaymentPurpose::SpontaneousPayment(payment_preimage) => {
21172117
assert_eq!(expected_preimage.unwrap(), *payment_preimage);
2118-
assert!(our_payment_secret.is_none());
2118+
assert_eq!(our_payment_secret, onion_fields.as_ref().unwrap().payment_secret);
21192119
},
21202120
}
21212121
assert_eq!(*amount_msat, recv_value);

lightning/src/ln/functional_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9442,7 +9442,7 @@ fn test_keysend_payments_to_public_node() {
94429442
let payer_pubkey = nodes[0].node.get_our_node_id();
94439443
let payee_pubkey = nodes[1].node.get_our_node_id();
94449444
let route_params = RouteParameters {
9445-
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
9445+
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
94469446
final_value_msat: 10000,
94479447
};
94489448
let scorer = test_utils::TestScorer::new();
@@ -9473,7 +9473,7 @@ fn test_keysend_payments_to_private_node() {
94739473

94749474
let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]);
94759475
let route_params = RouteParameters {
9476-
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
9476+
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
94779477
final_value_msat: 10000,
94789478
};
94799479
let network_graph = nodes[0].network_graph.clone();

lightning/src/ln/outbound_payment.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,9 @@ pub struct RecipientOnionFields {
414414
/// If you do not have one, the [`Route`] you pay over must not contain multiple paths as
415415
/// multi-path payments require a recipient-provided secret.
416416
///
417-
/// Note that for spontaneous payments most lightning nodes do not currently support MPP
418-
/// receives, thus you should generally never be providing a secret here for spontaneous
419-
/// payments.
417+
/// Some implementations may reject spontaneous payments with payment secrets, so you may only
418+
/// want to provide a secret for a spontaneous payment if MPP is needed and you know your
419+
/// recipient will not reject it.
420420
pub payment_secret: Option<PaymentSecret>,
421421
/// The payment metadata serves a similar purpose as [`Self::payment_secret`] but is of
422422
/// arbitrary length. This gives recipients substantially more flexibility to receive
@@ -447,10 +447,13 @@ impl RecipientOnionFields {
447447
}
448448

449449
/// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create
450-
/// payable HTLCs except for spontaneous payments, i.e. this should generally only be used for
451-
/// calls to [`ChannelManager::send_spontaneous_payment`].
450+
/// payable HTLCs except for single-path spontaneous payments, i.e. this should generally
451+
/// only be used for calls to [`ChannelManager::send_spontaneous_payment`]. If you are sending
452+
/// a spontaneous MPP this will not work as all MPP require payment secrets; you may
453+
/// instead want to use [`RecipientOnionFields::secret_only`].
452454
///
453455
/// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment
456+
/// [`RecipientOnionFields::secret_only`]: RecipientOnionFields::secret_only
454457
pub fn spontaneous_empty() -> Self {
455458
Self { payment_secret: None, payment_metadata: None }
456459
}

lightning/src/ln/payment_tests.rs

Lines changed: 174 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ use crate::sign::EntropySource;
1717
use crate::chain::transaction::OutPoint;
1818
use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
1919
use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
20-
use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS, RecentPaymentDetails, RecipientOnionFields};
20+
use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo};
2121
use crate::ln::features::InvoiceFeatures;
22-
use crate::ln::msgs;
22+
use crate::ln::{msgs, PaymentSecret, PaymentPreimage};
2323
use crate::ln::msgs::ChannelMessageHandler;
2424
use crate::ln::outbound_payment::Retry;
2525
use crate::routing::gossip::{EffectiveCapacity, RoutingFees};
26-
use crate::routing::router::{get_route, Path, PaymentParameters, Route, Router, RouteHint, RouteHintHop, RouteHop, RouteParameters};
26+
use crate::routing::router::{get_route, Path, PaymentParameters, Route, Router, RouteHint, RouteHintHop, RouteHop, RouteParameters, find_route};
2727
use crate::routing::scoring::ChannelUsage;
2828
use crate::util::test_utils;
2929
use crate::util::errors::APIError;
@@ -236,6 +236,177 @@ fn mpp_receive_timeout() {
236236
do_mpp_receive_timeout(false);
237237
}
238238

239+
#[test]
240+
fn test_mpp_keysend() {
241+
let mut mpp_keysend_config = test_default_channel_config();
242+
mpp_keysend_config.accept_mpp_keysend = true;
243+
let chanmon_cfgs = create_chanmon_cfgs(4);
244+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
245+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, Some(mpp_keysend_config)]);
246+
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
247+
248+
create_announced_chan_between_nodes(&nodes, 0, 1);
249+
create_announced_chan_between_nodes(&nodes, 0, 2);
250+
create_announced_chan_between_nodes(&nodes, 1, 3);
251+
create_announced_chan_between_nodes(&nodes, 2, 3);
252+
let network_graph = nodes[0].network_graph.clone();
253+
254+
let payer_pubkey = nodes[0].node.get_our_node_id();
255+
let payee_pubkey = nodes[3].node.get_our_node_id();
256+
let recv_value = 15_000_000;
257+
let route_params = RouteParameters {
258+
payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, true),
259+
final_value_msat: recv_value,
260+
};
261+
let scorer = test_utils::TestScorer::new();
262+
let random_seed_bytes = chanmon_cfgs[0].keys_manager.get_secure_random_bytes();
263+
let route = find_route(&payer_pubkey, &route_params, &network_graph, None, nodes[0].logger,
264+
&scorer, &(), &random_seed_bytes).unwrap();
265+
266+
let payment_preimage = PaymentPreimage([42; 32]);
267+
let payment_secret = PaymentSecret(payment_preimage.0);
268+
let payment_hash = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage),
269+
RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_preimage.0)).unwrap();
270+
check_added_monitors!(nodes[0], 2);
271+
272+
let expected_route: &[&[&Node]] = &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]];
273+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
274+
assert_eq!(events.len(), 2);
275+
276+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
277+
pass_along_path(&nodes[0], expected_route[0], recv_value, payment_hash.clone(),
278+
Some(payment_secret), ev.clone(), false, Some(payment_preimage));
279+
280+
let ev = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut events);
281+
pass_along_path(&nodes[0], expected_route[1], recv_value, payment_hash.clone(),
282+
Some(payment_secret), ev.clone(), true, Some(payment_preimage));
283+
claim_payment_along_route(&nodes[0], expected_route, false, payment_preimage);
284+
}
285+
286+
#[test]
287+
fn test_reject_mpp_keysend_htlc() {
288+
// This test enforces that we reject MPP keysend HTLCs if our config states we don't support
289+
// MPP keysend. When receiving a payment, if we don't support MPP keysend we'll reject the
290+
// payment if it's keysend and has a payment secret, never reaching our payment validation
291+
// logic. To check that we enforce rejecting MPP keysends in our payment logic, here we send
292+
// keysend payments without payment secrets, then modify them by adding payment secrets in the
293+
// final node in between receiving the HTLCs and actually processing them.
294+
let mut reject_mpp_keysend_cfg = test_default_channel_config();
295+
reject_mpp_keysend_cfg.accept_mpp_keysend = false;
296+
297+
let chanmon_cfgs = create_chanmon_cfgs(4);
298+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
299+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, Some(reject_mpp_keysend_cfg)]);
300+
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
301+
let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1).0.contents.short_channel_id;
302+
let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2).0.contents.short_channel_id;
303+
let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3).0.contents.short_channel_id;
304+
let (update_a, _, chan_4_channel_id, _) = create_announced_chan_between_nodes(&nodes, 2, 3);
305+
let chan_4_id = update_a.contents.short_channel_id;
306+
let amount = 40_000;
307+
let (mut route, payment_hash, payment_preimage, _) = get_route_and_payment_hash!(nodes[0], nodes[3], amount);
308+
309+
// Pay along nodes[1]
310+
route.paths[0].hops[0].pubkey = nodes[1].node.get_our_node_id();
311+
route.paths[0].hops[0].short_channel_id = chan_1_id;
312+
route.paths[0].hops[1].short_channel_id = chan_3_id;
313+
314+
let payment_id_0 = PaymentId(nodes[0].keys_manager.backing.get_secure_random_bytes());
315+
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), payment_id_0).unwrap();
316+
check_added_monitors!(nodes[0], 1);
317+
318+
let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
319+
let update_add_0 = update_0.update_add_htlcs[0].clone();
320+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add_0);
321+
commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);
322+
expect_pending_htlcs_forwardable!(nodes[1]);
323+
324+
check_added_monitors!(&nodes[1], 1);
325+
let update_1 = get_htlc_update_msgs!(nodes[1], nodes[3].node.get_our_node_id());
326+
let update_add_1 = update_1.update_add_htlcs[0].clone();
327+
nodes[3].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &update_add_1);
328+
commitment_signed_dance!(nodes[3], nodes[1], update_1.commitment_signed, false, true);
329+
330+
assert!(nodes[3].node.get_and_clear_pending_msg_events().is_empty());
331+
for (_, pending_forwards) in nodes[3].node.forward_htlcs.lock().unwrap().iter_mut() {
332+
for f in pending_forwards.iter_mut() {
333+
match f {
334+
&mut HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { ref mut forward_info, .. }) => {
335+
match forward_info.routing {
336+
PendingHTLCRouting::ReceiveKeysend { ref mut payment_data, .. } => {
337+
*payment_data = Some(msgs::FinalOnionHopData {
338+
payment_secret: PaymentSecret([42; 32]),
339+
total_msat: amount * 2,
340+
});
341+
},
342+
_ => panic!("Expected PendingHTLCRouting::ReceiveKeysend"),
343+
}
344+
},
345+
_ => {},
346+
}
347+
}
348+
}
349+
expect_pending_htlcs_forwardable!(nodes[3]);
350+
351+
// Pay along nodes[2]
352+
route.paths[0].hops[0].pubkey = nodes[2].node.get_our_node_id();
353+
route.paths[0].hops[0].short_channel_id = chan_2_id;
354+
route.paths[0].hops[1].short_channel_id = chan_4_id;
355+
356+
let payment_id_1 = PaymentId(nodes[0].keys_manager.backing.get_secure_random_bytes());
357+
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), payment_id_1).unwrap();
358+
check_added_monitors!(nodes[0], 1);
359+
360+
let update_2 = get_htlc_update_msgs!(nodes[0], nodes[2].node.get_our_node_id());
361+
let update_add_2 = update_2.update_add_htlcs[0].clone();
362+
nodes[2].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add_2);
363+
commitment_signed_dance!(nodes[2], nodes[0], &update_2.commitment_signed, false, true);
364+
expect_pending_htlcs_forwardable!(nodes[2]);
365+
366+
check_added_monitors!(&nodes[2], 1);
367+
let update_3 = get_htlc_update_msgs!(nodes[2], nodes[3].node.get_our_node_id());
368+
let update_add_3 = update_3.update_add_htlcs[0].clone();
369+
nodes[3].node.handle_update_add_htlc(&nodes[2].node.get_our_node_id(), &update_add_3);
370+
commitment_signed_dance!(nodes[3], nodes[2], update_3.commitment_signed, false, true);
371+
372+
assert!(nodes[3].node.get_and_clear_pending_msg_events().is_empty());
373+
for (_, pending_forwards) in nodes[3].node.forward_htlcs.lock().unwrap().iter_mut() {
374+
for f in pending_forwards.iter_mut() {
375+
match f {
376+
&mut HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { ref mut forward_info, .. }) => {
377+
match forward_info.routing {
378+
PendingHTLCRouting::ReceiveKeysend { ref mut payment_data, .. } => {
379+
*payment_data = Some(msgs::FinalOnionHopData {
380+
payment_secret: PaymentSecret([42; 32]),
381+
total_msat: amount * 2,
382+
});
383+
},
384+
_ => panic!("Expected PendingHTLCRouting::ReceiveKeysend"),
385+
}
386+
},
387+
_ => {},
388+
}
389+
}
390+
}
391+
expect_pending_htlcs_forwardable!(nodes[3]);
392+
check_added_monitors!(nodes[3], 1);
393+
394+
// Fail back along nodes[2]
395+
let update_fail_0 = get_htlc_update_msgs!(&nodes[3], &nodes[2].node.get_our_node_id());
396+
nodes[2].node.handle_update_fail_htlc(&nodes[3].node.get_our_node_id(), &update_fail_0.update_fail_htlcs[0]);
397+
commitment_signed_dance!(nodes[2], nodes[3], update_fail_0.commitment_signed, false);
398+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[2], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[3].node.get_our_node_id()), channel_id: chan_4_channel_id }]);
399+
check_added_monitors!(nodes[2], 1);
400+
401+
let update_fail_1 = get_htlc_update_msgs!(nodes[2], nodes[0].node.get_our_node_id());
402+
nodes[0].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &update_fail_1.update_fail_htlcs[0]);
403+
commitment_signed_dance!(nodes[0], nodes[2], update_fail_1.commitment_signed, false);
404+
405+
expect_payment_failed_conditions(&nodes[0], payment_hash, true, PaymentFailedConditions::new());
406+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[3], vec![HTLCDestination::FailedPayment { payment_hash }]);
407+
}
408+
409+
239410
#[test]
240411
fn no_pending_leak_on_initial_send_failure() {
241412
// In an earlier version of our payment tracking, we'd have a retry entry even when the initial

lightning/src/routing/router.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,8 +621,17 @@ impl PaymentParameters {
621621
///
622622
/// The `final_cltv_expiry_delta` should match the expected final CLTV delta the recipient has
623623
/// provided.
624-
pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32) -> Self {
625-
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")
624+
///
625+
/// Note that MPP keysend is not widely supported yet. The `allow_mpp` lets you choose
626+
/// whether your router will be allowed to find a multi-part route for this payment. If you
627+
/// set `allow_mpp` to true, you should ensure a payment secret is set on send, likely via
628+
/// [`RecipientOnionFields::secret_only`].
629+
///
630+
/// [`RecipientOnionFields::secret_only`]: crate::ln::channelmanager::RecipientOnionFields::secret_only
631+
pub fn for_keysend(payee_pubkey: PublicKey, final_cltv_expiry_delta: u32, allow_mpp: bool) -> Self {
632+
Self::from_node_id(payee_pubkey, final_cltv_expiry_delta)
633+
.with_bolt11_features(InvoiceFeatures::for_keysend(allow_mpp))
634+
.expect("PaymentParameters::from_node_id should always initialize the payee as unblinded")
626635
}
627636

628637
/// Includes the payee's features. Errors if the parameters were initialized with blinded payment

lightning/src/util/config.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,17 @@ pub struct UserConfig {
607607
/// [`ChannelManager::get_intercept_scid`]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
608608
/// [`Event::HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
609609
pub accept_intercept_htlcs: bool,
610+
/// If this is set to false, when receiving a keysend payment we'll fail it if it has multiple
611+
/// parts. If this is set to true, we'll accept the payment.
612+
///
613+
/// Setting this to true will break backwards compatibility upon downgrading to an LDK
614+
/// version < 0.0.116 while receiving an MPP keysend. If we have already received an MPP
615+
/// keysend, downgrading will cause us to fail to deserialize [`ChannelManager`].
616+
///
617+
/// Default value: false.
618+
///
619+
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
620+
pub accept_mpp_keysend: bool,
610621
}
611622

612623
impl Default for UserConfig {
@@ -619,6 +630,7 @@ impl Default for UserConfig {
619630
accept_inbound_channels: true,
620631
manually_accept_inbound_channels: false,
621632
accept_intercept_htlcs: false,
633+
accept_mpp_keysend: false,
622634
}
623635
}
624636
}

0 commit comments

Comments
 (0)