Skip to content

Commit 664abf2

Browse files
Support receiving keysend payments to blinded paths.
1 parent 154aa21 commit 664abf2

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,3 +1183,84 @@ fn conditionally_round_fwd_amt() {
11831183
let expected_fee = pass_claimed_payment_along_route(args);
11841184
expect_payment_sent(&nodes[0], payment_preimage, Some(Some(expected_fee)), true, true);
11851185
}
1186+
1187+
#[test]
1188+
fn blinded_keysend() {
1189+
let mut mpp_keysend_config = test_default_channel_config();
1190+
mpp_keysend_config.accept_mpp_keysend = true;
1191+
let chanmon_cfgs = create_chanmon_cfgs(3);
1192+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1193+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, Some(mpp_keysend_config)]);
1194+
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1195+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
1196+
let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents;
1197+
1198+
let amt_msat = 5000;
1199+
let (keysend_preimage, _, payment_secret) = get_payment_preimage_hash(&nodes[2], None, None);
1200+
let route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1,
1201+
1_0000_0000,
1202+
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(),
1203+
&[&chan_upd_1_2], &chanmon_cfgs[2].keys_manager);
1204+
1205+
let payment_hash = nodes[0].node.send_spontaneous_payment_with_retry(Some(keysend_preimage), RecipientOnionFields::spontaneous_empty(), PaymentId(keysend_preimage.0), route_params, Retry::Attempts(0)).unwrap();
1206+
check_added_monitors(&nodes[0], 1);
1207+
1208+
let expected_route: &[&[&Node]] = &[&[&nodes[1], &nodes[2]]];
1209+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
1210+
assert_eq!(events.len(), 1);
1211+
1212+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
1213+
pass_along_path(&nodes[0], expected_route[0], amt_msat, payment_hash, Some(payment_secret), ev.clone(), true, Some(keysend_preimage));
1214+
claim_payment_along_route(&nodes[0], expected_route, false, keysend_preimage);
1215+
}
1216+
1217+
#[test]
1218+
fn blinded_mpp_keysend() {
1219+
let mut mpp_keysend_config = test_default_channel_config();
1220+
mpp_keysend_config.accept_mpp_keysend = true;
1221+
let chanmon_cfgs = create_chanmon_cfgs(4);
1222+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
1223+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, Some(mpp_keysend_config)]);
1224+
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
1225+
1226+
create_announced_chan_between_nodes(&nodes, 0, 1);
1227+
create_announced_chan_between_nodes(&nodes, 0, 2);
1228+
let chan_1_3 = create_announced_chan_between_nodes(&nodes, 1, 3);
1229+
let chan_2_3 = create_announced_chan_between_nodes(&nodes, 2, 3);
1230+
1231+
let amt_msat = 15_000_000;
1232+
let (keysend_preimage, _, payment_secret) = get_payment_preimage_hash(&nodes[3], None, None);
1233+
let route_params = {
1234+
let pay_params = PaymentParameters::blinded(
1235+
vec![
1236+
blinded_payment_path(payment_secret, 1, 1_0000_0000,
1237+
vec![nodes[1].node.get_our_node_id(), nodes[3].node.get_our_node_id()], &[&chan_1_3.0.contents],
1238+
&chanmon_cfgs[3].keys_manager
1239+
),
1240+
blinded_payment_path(payment_secret, 1, 1_0000_0000,
1241+
vec![nodes[2].node.get_our_node_id(), nodes[3].node.get_our_node_id()], &[&chan_2_3.0.contents],
1242+
&chanmon_cfgs[3].keys_manager
1243+
),
1244+
]
1245+
)
1246+
.with_bolt12_features(channelmanager::provided_bolt12_invoice_features(&UserConfig::default()))
1247+
.unwrap();
1248+
RouteParameters::from_payment_params_and_value(pay_params, amt_msat)
1249+
};
1250+
1251+
let payment_hash = nodes[0].node.send_spontaneous_payment_with_retry(Some(keysend_preimage), RecipientOnionFields::spontaneous_empty(), PaymentId(keysend_preimage.0), route_params, Retry::Attempts(0)).unwrap();
1252+
check_added_monitors!(nodes[0], 2);
1253+
1254+
let expected_route: &[&[&Node]] = &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]];
1255+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
1256+
assert_eq!(events.len(), 2);
1257+
1258+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
1259+
pass_along_path(&nodes[0], expected_route[0], amt_msat, payment_hash.clone(),
1260+
Some(payment_secret), ev.clone(), false, Some(keysend_preimage));
1261+
1262+
let ev = remove_first_msg_event_to_node(&nodes[2].node.get_our_node_id(), &mut events);
1263+
pass_along_path(&nodes[0], expected_route[1], amt_msat, payment_hash.clone(),
1264+
Some(payment_secret), ev.clone(), true, Some(keysend_preimage));
1265+
claim_payment_along_route(&nodes[0], expected_route, false, keysend_preimage);
1266+
}

lightning/src/ln/channelmanager.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ pub enum PendingHTLCRouting {
200200
/// For HTLCs received by LDK, these will ultimately bubble back up as
201201
/// [`RecipientOnionFields::custom_tlvs`].
202202
custom_tlvs: Vec<(u64, Vec<u8>)>,
203+
/// Set if this HTLC is the final hop in a multi-hop blinded path.
204+
requires_blinded_error: bool,
203205
},
204206
}
205207

@@ -221,6 +223,7 @@ impl PendingHTLCRouting {
221223
match self {
222224
Self::Forward { blinded: Some(BlindedForward { failure, .. }), .. } => Some(*failure),
223225
Self::Receive { requires_blinded_error: true, .. } => Some(BlindedFailure::FromBlindedNode),
226+
Self::ReceiveKeysend { requires_blinded_error: true, .. } => Some(BlindedFailure::FromBlindedNode),
224227
_ => None,
225228
}
226229
}
@@ -4523,7 +4526,10 @@ where
45234526
(incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data },
45244527
Some(payment_data), phantom_shared_secret, onion_fields)
45254528
},
4526-
PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, incoming_cltv_expiry, custom_tlvs } => {
4529+
PendingHTLCRouting::ReceiveKeysend {
4530+
payment_data, payment_preimage, payment_metadata,
4531+
incoming_cltv_expiry, custom_tlvs, requires_blinded_error: _
4532+
} => {
45274533
let onion_fields = RecipientOnionFields {
45284534
payment_secret: payment_data.as_ref().map(|data| data.payment_secret),
45294535
payment_metadata,
@@ -9766,6 +9772,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
97669772
},
97679773
(2, ReceiveKeysend) => {
97689774
(0, payment_preimage, required),
9775+
(1, requires_blinded_error, (default_value, false)),
97699776
(2, incoming_cltv_expiry, required),
97709777
(3, payment_metadata, option),
97719778
(4, payment_data, option), // Added in 0.0.116

lightning/src/ln/onion_payment.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ pub(super) fn create_recv_pending_htlc_info(
139139
cltv_expiry_height, payment_metadata, false),
140140
msgs::InboundOnionPayload::BlindedReceive {
141141
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
142-
intro_node_blinding_point, payment_constraints, ..
142+
intro_node_blinding_point, payment_constraints, keysend_preimage, ..
143143
} => {
144144
check_blinded_payment_constraints(
145145
sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
@@ -152,8 +152,9 @@ pub(super) fn create_recv_pending_htlc_info(
152152
}
153153
})?;
154154
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
155-
(Some(payment_data), None, Vec::new(), sender_intended_htlc_amt_msat, cltv_expiry_height,
156-
None, intro_node_blinding_point.is_none())
155+
(Some(payment_data), keysend_preimage, Vec::new(),
156+
sender_intended_htlc_amt_msat, cltv_expiry_height, None,
157+
intro_node_blinding_point.is_none())
157158
}
158159
msgs::InboundOnionPayload::Forward { .. } => {
159160
return Err(InboundHTLCErr {
@@ -232,6 +233,7 @@ pub(super) fn create_recv_pending_htlc_info(
232233
payment_metadata,
233234
incoming_cltv_expiry: onion_cltv_expiry,
234235
custom_tlvs,
236+
requires_blinded_error,
235237
}
236238
} else if let Some(data) = payment_data {
237239
PendingHTLCRouting::Receive {

0 commit comments

Comments
 (0)