Skip to content

Commit ce6b2dd

Browse files
committed
Distinguish Between Sender and User Custom TLVs
- This update introduces a clear separation between two types of custom TLVs: those sent by the sender for the user, and those added by the user to the reply path, which are expected to return with the response. - This commit establishes this distinction in the codebase at relevant points. - The next commit will build on this by providing an interface for users to add their own custom TLVs to the reply path, allowing them to receive specific data back in the response. Note: 1. Similar to keysend, for serialization purposes, user_custom_tlv are assigned a specific TLV number. 2. For uniformity, user_custom_tlv are assigned the lowest possible odd number after (1 << 16), which is 65537.
1 parent 8f320f9 commit ce6b2dd

9 files changed

+261
-147
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,7 @@ fn custom_tlvs_to_blinded_path() {
13891389
);
13901390

13911391
let recipient_onion_fields = RecipientOnionFields::spontaneous_empty()
1392-
.with_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])])
1392+
.with_sender_custom_tlvs(vec![((1 << 16) + 3, vec![42, 42])])
13931393
.unwrap();
13941394
nodes[0].node.send_payment(payment_hash, recipient_onion_fields.clone(),
13951395
PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
@@ -1402,11 +1402,11 @@ fn custom_tlvs_to_blinded_path() {
14021402
let path = &[&nodes[1]];
14031403
let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, ev)
14041404
.with_payment_secret(payment_secret)
1405-
.with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone());
1405+
.with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone());
14061406
do_pass_along_path(args);
14071407
claim_payment_along_route(
14081408
ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], payment_preimage)
1409-
.with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone())
1409+
.with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone())
14101410
);
14111411
}
14121412

lightning/src/ln/channelmanager.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,14 @@ pub enum PendingHTLCRouting {
193193
///
194194
/// For HTLCs received by LDK, this will ultimately be exposed in
195195
/// [`Event::PaymentClaimable::onion_fields`] as
196-
/// [`RecipientOnionFields::custom_tlvs`].
197-
custom_tlvs: Vec<(u64, Vec<u8>)>,
196+
/// [`RecipientOnionFields::sender_custom_tlvs`].
197+
sender_custom_tlvs: Vec<(u64, Vec<u8>)>,
198+
/// Custom TLVs set by the receiver in the blinded path used to reach them.
199+
///
200+
/// For HTLCs received by LDK, this will be exposed in
201+
/// [`Event::PaymentClaimable::onion_fields`] as
202+
/// [`RecipientOnionFields::user_custom_tlvs`].
203+
user_custom_tlvs: Vec<u8>,
198204
/// Set if this HTLC is the final hop in a multi-hop blinded path.
199205
requires_blinded_error: bool,
200206
},
@@ -223,8 +229,13 @@ pub enum PendingHTLCRouting {
223229
/// Custom TLVs which were set by the sender.
224230
///
225231
/// For HTLCs received by LDK, these will ultimately bubble back up as
226-
/// [`RecipientOnionFields::custom_tlvs`].
227-
custom_tlvs: Vec<(u64, Vec<u8>)>,
232+
/// [`RecipientOnionFields::sender_custom_tlvs`].
233+
sender_custom_tlvs: Vec<(u64, Vec<u8>)>,
234+
/// Custom TLVs set by the receiver in the blinded path used to reach them.
235+
///
236+
/// For HTLCs received by LDK, these will ultimately bubble back up as
237+
/// [`RecipientOnionFields::user_custom_tlvs`].
238+
user_custom_tlvs: Vec<u8>,
228239
/// Set if this HTLC is the final hop in a multi-hop blinded path.
229240
requires_blinded_error: bool,
230241
/// Set if we are receiving a keysend to a blinded path, meaning we created the
@@ -939,10 +950,10 @@ impl ClaimablePayments {
939950
}
940951
}
941952

942-
if let Some(RecipientOnionFields { custom_tlvs, .. }) = &payment.onion_fields {
943-
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
953+
if let Some(RecipientOnionFields { sender_custom_tlvs, .. }) = &payment.onion_fields {
954+
if !custom_tlvs_known && sender_custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
944955
log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
945-
&payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
956+
&payment_hash, log_iter!(sender_custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
946957
return Err(payment.htlcs);
947958
}
948959
}
@@ -6051,25 +6062,26 @@ where
60516062
) = match routing {
60526063
PendingHTLCRouting::Receive {
60536064
payment_data, payment_metadata, payment_context,
6054-
incoming_cltv_expiry, phantom_shared_secret, custom_tlvs,
6065+
incoming_cltv_expiry, phantom_shared_secret, sender_custom_tlvs, user_custom_tlvs,
60556066
requires_blinded_error: _
60566067
} => {
60576068
let _legacy_hop_data = Some(payment_data.clone());
60586069
let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret),
6059-
payment_metadata, custom_tlvs };
6070+
payment_metadata, sender_custom_tlvs, user_custom_tlvs };
60606071
(incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data },
60616072
Some(payment_data), payment_context, phantom_shared_secret, onion_fields,
60626073
true)
60636074
},
60646075
PendingHTLCRouting::ReceiveKeysend {
60656076
payment_data, payment_preimage, payment_metadata,
6066-
incoming_cltv_expiry, custom_tlvs, requires_blinded_error: _,
6077+
incoming_cltv_expiry, sender_custom_tlvs, user_custom_tlvs, requires_blinded_error: _,
60676078
has_recipient_created_payment_secret,
60686079
} => {
60696080
let onion_fields = RecipientOnionFields {
60706081
payment_secret: payment_data.as_ref().map(|data| data.payment_secret),
60716082
payment_metadata,
6072-
custom_tlvs,
6083+
sender_custom_tlvs,
6084+
user_custom_tlvs,
60736085
};
60746086
(incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage),
60756087
payment_data, None, None, onion_fields, has_recipient_created_payment_secret)
@@ -12385,18 +12397,20 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
1238512397
(1, phantom_shared_secret, option),
1238612398
(2, incoming_cltv_expiry, required),
1238712399
(3, payment_metadata, option),
12388-
(5, custom_tlvs, optional_vec),
12400+
(5, sender_custom_tlvs, optional_vec),
1238912401
(7, requires_blinded_error, (default_value, false)),
1239012402
(9, payment_context, option),
12403+
(11, user_custom_tlvs, optional_vec),
1239112404
},
1239212405
(2, ReceiveKeysend) => {
1239312406
(0, payment_preimage, required),
1239412407
(1, requires_blinded_error, (default_value, false)),
1239512408
(2, incoming_cltv_expiry, required),
1239612409
(3, payment_metadata, option),
1239712410
(4, payment_data, option), // Added in 0.0.116
12398-
(5, custom_tlvs, optional_vec),
12411+
(5, sender_custom_tlvs, optional_vec),
1239912412
(7, has_recipient_created_payment_secret, (default_value, false)),
12413+
(9, user_custom_tlvs, optional_vec),
1240012414
},
1240112415
);
1240212416

@@ -15361,7 +15375,8 @@ mod tests {
1536115375
payment_data: Some(msgs::FinalOnionHopData {
1536215376
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
1536315377
}),
15364-
custom_tlvs: Vec::new(),
15378+
sender_custom_tlvs: Vec::new(),
15379+
user_custom_tlvs: Vec::new(),
1536515380
};
1536615381
// Check that if the amount we received + the penultimate hop extra fee is less than the sender
1536715382
// intended amount, we fail the payment.
@@ -15383,7 +15398,8 @@ mod tests {
1538315398
payment_data: Some(msgs::FinalOnionHopData {
1538415399
payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat,
1538515400
}),
15386-
custom_tlvs: Vec::new(),
15401+
sender_custom_tlvs: Vec::new(),
15402+
user_custom_tlvs: Vec::new(),
1538715403
};
1538815404
let current_height: u32 = node[0].node.best_block.read().unwrap().height;
1538915405
assert!(create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
@@ -15407,7 +15423,8 @@ mod tests {
1540715423
payment_data: Some(msgs::FinalOnionHopData {
1540815424
payment_secret: PaymentSecret([0; 32]), total_msat: 100,
1540915425
}),
15410-
custom_tlvs: Vec::new(),
15426+
sender_custom_tlvs: Vec::new(),
15427+
user_custom_tlvs: Vec::new(),
1541115428
}, [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None, current_height);
1541215429

1541315430
// Should not return an error as this condition:

lightning/src/ln/functional_test_utils.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,7 +2633,8 @@ pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
26332633
pub clear_recipient_events: bool,
26342634
pub expected_preimage: Option<PaymentPreimage>,
26352635
pub is_probe: bool,
2636-
pub custom_tlvs: Vec<(u64, Vec<u8>)>,
2636+
pub sender_custom_tlvs: Vec<(u64, Vec<u8>)>,
2637+
pub user_custom_tlvs: Vec<u8>,
26372638
pub payment_metadata: Option<Vec<u8>>,
26382639
pub expected_failure: Option<HTLCDestination>,
26392640
}
@@ -2646,7 +2647,7 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
26462647
Self {
26472648
origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event,
26482649
payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None,
2649-
is_probe: false, custom_tlvs: Vec::new(), payment_metadata: None, expected_failure: None,
2650+
is_probe: false, sender_custom_tlvs: Vec::new(), user_custom_tlvs: Vec::new(), payment_metadata: None, expected_failure: None,
26502651
}
26512652
}
26522653
pub fn without_clearing_recipient_events(mut self) -> Self {
@@ -2670,8 +2671,12 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> {
26702671
self.expected_preimage = Some(payment_preimage);
26712672
self
26722673
}
2673-
pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
2674-
self.custom_tlvs = custom_tlvs;
2674+
pub fn with_sender_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
2675+
self.sender_custom_tlvs = custom_tlvs;
2676+
self
2677+
}
2678+
pub fn with_user_custom_tlvs(mut self, custom_tlvs: Vec<u8>) -> Self {
2679+
self.user_custom_tlvs = custom_tlvs;
26752680
self
26762681
}
26772682
pub fn with_payment_metadata(mut self, payment_metadata: Vec<u8>) -> Self {
@@ -2689,8 +2694,8 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event>
26892694
let PassAlongPathArgs {
26902695
origin_node, expected_path, recv_value, payment_hash: our_payment_hash,
26912696
payment_secret: our_payment_secret, event: ev, payment_claimable_expected,
2692-
clear_recipient_events, expected_preimage, is_probe, custom_tlvs, payment_metadata,
2693-
expected_failure
2697+
clear_recipient_events, expected_preimage, is_probe, sender_custom_tlvs, user_custom_tlvs,
2698+
payment_metadata, expected_failure
26942699
} = args;
26952700

26962701
let mut payment_event = SendEvent::from_event(ev);
@@ -2723,7 +2728,8 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option<Event>
27232728
assert_eq!(our_payment_hash, *payment_hash);
27242729
assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap());
27252730
assert!(onion_fields.is_some());
2726-
assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs);
2731+
assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs);
2732+
assert_eq!(onion_fields.as_ref().unwrap().user_custom_tlvs, user_custom_tlvs);
27272733
assert_eq!(onion_fields.as_ref().unwrap().payment_metadata, payment_metadata);
27282734
match &purpose {
27292735
PaymentPurpose::Bolt11InvoicePayment { payment_preimage, payment_secret, .. } => {
@@ -2842,7 +2848,8 @@ pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
28422848
pub expected_min_htlc_overpay: Vec<u32>,
28432849
pub skip_last: bool,
28442850
pub payment_preimage: PaymentPreimage,
2845-
pub custom_tlvs: Vec<(u64, Vec<u8>)>,
2851+
pub sender_custom_tlvs: Vec<(u64, Vec<u8>)>,
2852+
pub user_custom_tlvs: Vec<u8>,
28462853
// Allow forwarding nodes to have taken 1 msat more fee than expected based on the downstream
28472854
// fulfill amount.
28482855
//
@@ -2861,7 +2868,7 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
28612868
Self {
28622869
origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()],
28632870
expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage,
2864-
allow_1_msat_fee_overpay: false, custom_tlvs: vec![],
2871+
allow_1_msat_fee_overpay: false, sender_custom_tlvs: vec![], user_custom_tlvs: vec![],
28652872
}
28662873
}
28672874
pub fn skip_last(mut self, skip_last: bool) -> Self {
@@ -2880,16 +2887,16 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> {
28802887
self.allow_1_msat_fee_overpay = true;
28812888
self
28822889
}
2883-
pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
2884-
self.custom_tlvs = custom_tlvs;
2890+
pub fn with_sender_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec<u8>)>) -> Self {
2891+
self.sender_custom_tlvs = custom_tlvs;
28852892
self
28862893
}
28872894
}
28882895

28892896
pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 {
28902897
let ClaimAlongRouteArgs {
28912898
origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last,
2892-
payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, custom_tlvs,
2899+
payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, sender_custom_tlvs, user_custom_tlvs,
28932900
} = args;
28942901
let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
28952902
assert_eq!(claim_event.len(), 1);
@@ -2909,7 +2916,8 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 {
29092916
assert_eq!(preimage, our_payment_preimage);
29102917
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
29112918
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2912-
assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs);
2919+
assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs);
2920+
assert_eq!(onion_fields.as_ref().unwrap().user_custom_tlvs, user_custom_tlvs);
29132921
check_claimed_htlcs_match_route(origin_node, expected_paths, htlcs);
29142922
fwd_amt_msat = amount_msat;
29152923
},
@@ -2926,7 +2934,8 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 {
29262934
assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]);
29272935
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
29282936
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2929-
assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs);
2937+
assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs);
2938+
assert_eq!(onion_fields.as_ref().unwrap().user_custom_tlvs, user_custom_tlvs);
29302939
check_claimed_htlcs_match_route(origin_node, expected_paths, htlcs);
29312940
fwd_amt_msat = amount_msat;
29322941
}

0 commit comments

Comments
 (0)