Skip to content

Commit dec3fb3

Browse files
committed
Enforce explicit claims on payments with even custom TLVs
Because we don't know which custom TLV type numbers the user is expecting (and it would be cumbersome for them to tell us), instead of failing unknown even custom TLVs on deserialization, we accept all custom TLVs, and pass them to the user to check whether they recognize them and choose to fail back if they don't. However, a user may not check for custom TLVs, in which case we should reject any even custom TLVs as unknown. This commit makes sure a user must explicitly accept a payment with even custom TLVs, by (1) making the default `ChannelManager::claim_funds` fail if the payment had even custom TLVs and (2) adding a new function `ChannelManager::claim_funds_with_known_custom_tlvs` that accepts them. This commit also refactors our custom TLVs test and updates various documentation to account for this.
1 parent 8ff1604 commit dec3fb3

File tree

4 files changed

+86
-9
lines changed

4 files changed

+86
-9
lines changed

lightning/src/events/mod.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,19 @@ pub enum Event {
356356
/// Note that if the preimage is not known, you should call
357357
/// [`ChannelManager::fail_htlc_backwards`] or [`ChannelManager::fail_htlc_backwards_with_reason`]
358358
/// to free up resources for this HTLC and avoid network congestion.
359-
/// If you fail to call either [`ChannelManager::claim_funds`], [`ChannelManager::fail_htlc_backwards`],
360-
/// or [`ChannelManager::fail_htlc_backwards_with_reason`] within the HTLC's timeout, the HTLC will be
361-
/// automatically failed.
359+
///
360+
/// If [`Event::PaymentClaimable::onion_fields`] is `Some`, and includes custom TLVs with even type
361+
/// numbers, you should use [`ChannelManager::fail_htlc_backwards_with_reason`] with
362+
/// [`FailureCode::InvalidOnionPayload`] if you fail to understand and handle the contents, or
363+
/// [`ChannelManager::claim_funds_with_known_custom_tlvs`] upon successful handling.
364+
/// If you don't intend to check for custom TLVs, you can simply use
365+
/// [`ChannelManager::claim_funds`], which will automatically fail back even custom TLVs.
366+
///
367+
/// If you fail to call [`ChannelManager::claim_funds`],
368+
/// [`ChannelManager::claim_funds_with_known_custom_tlvs`],
369+
/// [`ChannelManager::fail_htlc_backwards`], or
370+
/// [`ChannelManager::fail_htlc_backwards_with_reason`] within the HTLC's timeout, the HTLC will
371+
/// be automatically failed.
362372
///
363373
/// # Note
364374
/// LDK will not stop an inbound payment from being paid multiple times, so multiple
@@ -370,6 +380,8 @@ pub enum Event {
370380
/// This event used to be called `PaymentReceived` in LDK versions 0.0.112 and earlier.
371381
///
372382
/// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds
383+
/// [`ChannelManager::claim_funds_with_known_custom_tlvs`]: crate::ln::channelmanager::ChannelManager::claim_funds_with_known_custom_tlvs
384+
/// [`FailureCode::InvalidOnionPayload`]: crate::ln::channelmanager::FailureCode::InvalidOnionPayload
373385
/// [`ChannelManager::fail_htlc_backwards`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards
374386
/// [`ChannelManager::fail_htlc_backwards_with_reason`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards_with_reason
375387
PaymentClaimable {

lightning/src/ln/channelmanager.rs

+39
Original file line numberDiff line numberDiff line change
@@ -4759,13 +4759,35 @@ where
47594759
/// event matches your expectation. If you fail to do so and call this method, you may provide
47604760
/// the sender "proof-of-payment" when they did not fulfill the full expected payment.
47614761
///
4762+
/// This function will fail the payment if it has custom TLVs with even type numbers, as we
4763+
/// will assume they are unknown. If you intend to accept even custom TLVs, you should use
4764+
/// [`claim_funds_with_known_custom_tlvs`].
4765+
///
47624766
/// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
47634767
/// [`Event::PaymentClaimable::claim_deadline`]: crate::events::Event::PaymentClaimable::claim_deadline
47644768
/// [`Event::PaymentClaimed`]: crate::events::Event::PaymentClaimed
47654769
/// [`process_pending_events`]: EventsProvider::process_pending_events
47664770
/// [`create_inbound_payment`]: Self::create_inbound_payment
47674771
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
4772+
/// [`claim_funds_with_known_custom_tlvs`]: Self::claim_funds_with_known_custom_tlvs
47684773
pub fn claim_funds(&self, payment_preimage: PaymentPreimage) {
4774+
self.claim_payment_internal(payment_preimage, false);
4775+
}
4776+
4777+
/// This is a variant of [`claim_funds`] that allows accepting a payment with custom TLVs with
4778+
/// even type numbers.
4779+
///
4780+
/// # Note
4781+
///
4782+
/// You MUST check you've understood all even TLVs before using this to
4783+
/// claim, otherwise you may unintentionally agree to some protocol you do not understand.
4784+
///
4785+
/// [`claim_funds`]: Self::claim_funds
4786+
pub fn claim_funds_with_known_custom_tlvs(&self, payment_preimage: PaymentPreimage) {
4787+
self.claim_payment_internal(payment_preimage, true);
4788+
}
4789+
4790+
fn claim_payment_internal(&self, payment_preimage: PaymentPreimage, custom_tlvs_known: bool) {
47694791
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
47704792

47714793
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -4792,6 +4814,23 @@ where
47924814
log_error!(self.logger, "Got a duplicate pending claimable event on payment hash {}! Please report this bug",
47934815
log_bytes!(payment_hash.0));
47944816
}
4817+
4818+
if let Some(RecipientOnionFields { ref custom_tlvs, .. }) = payment.onion_fields {
4819+
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
4820+
log_info!(self.logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
4821+
log_bytes!(payment_hash.0), log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
4822+
claimable_payments.pending_claiming_payments.remove(&payment_hash);
4823+
mem::drop(claimable_payments);
4824+
for htlc in payment.htlcs {
4825+
let reason = self.get_htlc_fail_reason_from_failure_code(FailureCode::InvalidOnionPayload(None), &htlc);
4826+
let source = HTLCSource::PreviousHopData(htlc.prev_hop);
4827+
let receiver = HTLCDestination::FailedPayment { payment_hash };
4828+
self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
4829+
}
4830+
return;
4831+
}
4832+
}
4833+
47954834
payment.htlcs
47964835
} else { return; }
47974836
};

lightning/src/ln/functional_test_utils.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2250,7 +2250,10 @@ pub fn do_claim_payment_along_route_with_extra_penultimate_hop_fees<'a, 'b, 'c>(
22502250
assert_eq!(path.last().unwrap().node.get_our_node_id(), expected_paths[0].last().unwrap().node.get_our_node_id());
22512251
}
22522252
expected_paths[0].last().unwrap().node.claim_funds(our_payment_preimage);
2253+
pass_claimed_payment_along_route(origin_node, expected_paths, expected_extra_fees, skip_last, our_payment_preimage)
2254+
}
22532255

2256+
pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths: &[&[&Node<'a, 'b, 'c>]], expected_extra_fees: &[u32], skip_last: bool, our_payment_preimage: PaymentPreimage) -> u64 {
22542257
let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
22552258
assert_eq!(claim_event.len(), 1);
22562259
match claim_event[0] {

lightning/src/ln/payment_tests.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -3386,12 +3386,20 @@ fn claim_from_closed_chan() {
33863386
}
33873387

33883388
#[test]
3389-
fn test_custom_tlvs() {
3390-
do_test_custom_tlvs(true);
3391-
do_test_custom_tlvs(false);
3389+
fn test_custom_tlvs_basic() {
3390+
do_test_custom_tlvs(false, false, false);
3391+
do_test_custom_tlvs(true, false, false);
33923392
}
33933393

3394-
fn do_test_custom_tlvs(spontaneous: bool) {
3394+
#[test]
3395+
fn test_custom_tlvs_explicit_claim() {
3396+
// Test that when receiving even custom TLVs the user must explicitly accept in case they
3397+
// are unknown.
3398+
do_test_custom_tlvs(false, true, false);
3399+
do_test_custom_tlvs(false, true, true);
3400+
}
3401+
3402+
fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) {
33953403
let chanmon_cfgs = create_chanmon_cfgs(2);
33963404
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
33973405
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None; 2]);
@@ -3403,7 +3411,7 @@ fn do_test_custom_tlvs(spontaneous: bool) {
34033411
let (mut route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat);
34043412
let payment_id = PaymentId(our_payment_hash.0);
34053413
let custom_tlvs = vec![
3406-
(5482373483, vec![1, 2, 3, 4]),
3414+
(if even_tlvs { 5482373482 } else { 5482373483 }, vec![1, 2, 3, 4]),
34073415
(5482373487, vec![0x42u8; 16]),
34083416
];
34093417
let onion_fields = RecipientOnionFields {
@@ -3446,7 +3454,22 @@ fn do_test_custom_tlvs(spontaneous: bool) {
34463454
_ => panic!("Unexpected event"),
34473455
}
34483456

3449-
claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
3457+
match (known_tlvs, even_tlvs) {
3458+
(true, _) => {
3459+
nodes[1].node.claim_funds_with_known_custom_tlvs(our_payment_preimage);
3460+
let expected_total_fee_msat = pass_claimed_payment_along_route(&nodes[0], &[&[&nodes[1]]], &[0; 1], false, our_payment_preimage);
3461+
expect_payment_sent!(&nodes[0], our_payment_preimage, Some(expected_total_fee_msat));
3462+
},
3463+
(false, false) => {
3464+
claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
3465+
},
3466+
(false, true) => {
3467+
nodes[1].node.claim_funds(our_payment_preimage);
3468+
let expected_destinations = vec![HTLCDestination::FailedPayment { payment_hash: our_payment_hash }];
3469+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], expected_destinations);
3470+
pass_failed_payment_back(&nodes[0], &[&[&nodes[1]]], false, our_payment_hash, PaymentFailureReason::RecipientRejected);
3471+
}
3472+
}
34503473
}
34513474

34523475
#[test]

0 commit comments

Comments
 (0)