Skip to content

Commit 3b30791

Browse files
committed
Handle receiving custom HTLC TLVs
This completes basic receiver-side support for custom TLVs and adds functional testing for sending and receiving.
1 parent 5db2070 commit 3b30791

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,15 @@ pub(super) enum PendingHTLCRouting {
110110
payment_metadata: Option<Vec<u8>>,
111111
incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
112112
phantom_shared_secret: Option<[u8; 32]>,
113+
custom_tlvs: Option<Vec<(u64, Vec<u8>)>>,
113114
},
114115
ReceiveKeysend {
115116
/// This was added in 0.0.116 and will break deserialization on downgrades.
116117
payment_data: Option<msgs::FinalOnionHopData>,
117118
payment_preimage: PaymentPreimage,
118119
payment_metadata: Option<Vec<u8>>,
119120
incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
121+
custom_tlvs: Option<Vec<(u64, Vec<u8>)>>,
120122
},
121123
}
122124

@@ -2485,13 +2487,15 @@ where
24852487
payment_preimage,
24862488
payment_metadata,
24872489
incoming_cltv_expiry: hop_data.outgoing_cltv_value,
2490+
custom_tlvs,
24882491
}
24892492
} else if let Some(data) = payment_data {
24902493
PendingHTLCRouting::Receive {
24912494
payment_data: data,
24922495
payment_metadata,
24932496
incoming_cltv_expiry: hop_data.outgoing_cltv_value,
24942497
phantom_shared_secret,
2498+
custom_tlvs,
24952499
}
24962500
} else {
24972501
return Err(ReceiveError {
@@ -3629,18 +3633,18 @@ where
36293633
}
36303634
}) => {
36313635
let (cltv_expiry, onion_payload, payment_data, phantom_shared_secret, mut onion_fields) = match routing {
3632-
PendingHTLCRouting::Receive { payment_data, payment_metadata, incoming_cltv_expiry, phantom_shared_secret } => {
3636+
PendingHTLCRouting::Receive { payment_data, payment_metadata, incoming_cltv_expiry, phantom_shared_secret, custom_tlvs } => {
36333637
let _legacy_hop_data = Some(payment_data.clone());
36343638
let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret),
3635-
payment_metadata, custom_tlvs: None };
3639+
payment_metadata, custom_tlvs };
36363640
(incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data },
36373641
Some(payment_data), phantom_shared_secret, onion_fields)
36383642
},
3639-
PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, incoming_cltv_expiry } => {
3643+
PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, incoming_cltv_expiry, custom_tlvs } => {
36403644
let onion_fields = RecipientOnionFields {
36413645
payment_secret: payment_data.as_ref().map(|data| data.payment_secret),
36423646
payment_metadata,
3643-
custom_tlvs: None,
3647+
custom_tlvs,
36443648
};
36453649
(incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage),
36463650
payment_data, None, onion_fields)
@@ -7249,12 +7253,14 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
72497253
(1, phantom_shared_secret, option),
72507254
(2, incoming_cltv_expiry, required),
72517255
(3, payment_metadata, option),
7256+
(5, custom_tlvs, option),
72527257
},
72537258
(2, ReceiveKeysend) => {
72547259
(0, payment_preimage, required),
72557260
(2, incoming_cltv_expiry, required),
72567261
(3, payment_metadata, option),
72577262
(4, payment_data, option), // Added in 0.0.116
7263+
(5, custom_tlvs, option),
72587264
},
72597265
;);
72607266

lightning/src/ln/payment_tests.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::chain::{ChannelMonitorUpdateStatus, Confirm, Listen, Watch};
1515
use crate::chain::channelmonitor::{ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
1616
use crate::sign::EntropySource;
1717
use crate::chain::transaction::OutPoint;
18-
use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
18+
use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason, PaymentPurpose};
1919
use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
2020
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;
@@ -3196,6 +3196,71 @@ fn claim_from_closed_chan() {
31963196
do_claim_from_closed_chan(false);
31973197
}
31983198

3199+
#[test]
3200+
fn test_custom_tlvs() {
3201+
do_test_custom_tlvs(true);
3202+
do_test_custom_tlvs(false);
3203+
}
3204+
3205+
fn do_test_custom_tlvs(spontaneous: bool) {
3206+
let chanmon_cfgs = create_chanmon_cfgs(2);
3207+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
3208+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None; 2]);
3209+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
3210+
3211+
create_announced_chan_between_nodes(&nodes, 0, 1);
3212+
3213+
let amt_msat = 100_000;
3214+
let (mut route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat);
3215+
let payment_id = PaymentId(our_payment_hash.0);
3216+
let custom_tlvs = vec![
3217+
(5482373483, vec![1, 2, 3, 4]),
3218+
(5482373487, vec![0x42u8; 16]),
3219+
];
3220+
let onion_fields = RecipientOnionFields {
3221+
payment_secret: if spontaneous { None } else { Some(our_payment_secret) },
3222+
payment_metadata: None,
3223+
custom_tlvs: Some(custom_tlvs.clone())
3224+
};
3225+
if spontaneous {
3226+
nodes[0].node.send_spontaneous_payment(&route, Some(our_payment_preimage), onion_fields, payment_id).unwrap();
3227+
} else {
3228+
nodes[0].node.send_payment_with_route(&route, our_payment_hash, onion_fields, payment_id).unwrap();
3229+
}
3230+
check_added_monitors(&nodes[0], 1);
3231+
3232+
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
3233+
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
3234+
let mut payment_event = SendEvent::from_event(ev);
3235+
3236+
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event.msgs[0]);
3237+
check_added_monitors!(&nodes[1], 0);
3238+
commitment_signed_dance!(nodes[1], nodes[0], payment_event.commitment_msg, false);
3239+
expect_pending_htlcs_forwardable!(nodes[1]);
3240+
3241+
let events = nodes[1].node.get_and_clear_pending_events();
3242+
assert_eq!(events.len(), 1);
3243+
match events[0] {
3244+
Event::PaymentClaimable { ref purpose, amount_msat, ref onion_fields, .. } => {
3245+
match &purpose {
3246+
PaymentPurpose::InvoicePayment { payment_secret, .. } => {
3247+
assert_eq!(our_payment_secret, *payment_secret);
3248+
assert_eq!(Some(*payment_secret), onion_fields.as_ref().unwrap().payment_secret);
3249+
},
3250+
PaymentPurpose::SpontaneousPayment(payment_preimage) => {
3251+
assert_eq!(our_payment_preimage, *payment_preimage);
3252+
},
3253+
}
3254+
assert_eq!(amount_msat, amt_msat);
3255+
assert_eq!(onion_fields.clone().unwrap().custom_tlvs().clone().unwrap(), custom_tlvs);
3256+
},
3257+
_ => panic!("Unexpected event"),
3258+
}
3259+
3260+
claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
3261+
}
3262+
3263+
31993264
fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) {
32003265
// Check that a payment metadata received on one HTLC that doesn't match the one received on
32013266
// another results in the HTLC being rejected.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Backwards Compatibility
2+
3+
* Since the addition of custom HTLC TLV support in 0.0.116, if you downgrade you may unintentionally accept payments with features you don't understand.

0 commit comments

Comments
 (0)