Skip to content

Commit 1db481f

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 05789d4 commit 1db481f

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
@@ -4746,13 +4746,35 @@ where
47464746
/// event matches your expectation. If you fail to do so and call this method, you may provide
47474747
/// the sender "proof-of-payment" when they did not fulfill the full expected payment.
47484748
///
4749+
/// This function will fail the payment if it has custom TLVs with even type numbers, as we
4750+
/// will assume they are unknown. If you intend to accept even custom TLVs, you should use
4751+
/// [`claim_funds_with_known_custom_tlvs`].
4752+
///
47494753
/// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
47504754
/// [`Event::PaymentClaimable::claim_deadline`]: crate::events::Event::PaymentClaimable::claim_deadline
47514755
/// [`Event::PaymentClaimed`]: crate::events::Event::PaymentClaimed
47524756
/// [`process_pending_events`]: EventsProvider::process_pending_events
47534757
/// [`create_inbound_payment`]: Self::create_inbound_payment
47544758
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
4759+
/// [`claim_funds_with_known_custom_tlvs`]: Self::claim_funds_with_known_custom_tlvs
47554760
pub fn claim_funds(&self, payment_preimage: PaymentPreimage) {
4761+
self.claim_payment_internal(payment_preimage, false);
4762+
}
4763+
4764+
/// This is a variant of [`claim_funds`] that allows accepting a payment with custom TLVs with
4765+
/// even type numbers.
4766+
///
4767+
/// # Note
4768+
///
4769+
/// You MUST check you've understood all even TLVs before using this to
4770+
/// claim, otherwise you may unintentionally agree to some protocol you do not understand.
4771+
///
4772+
/// [`claim_funds`]: Self::claim_funds
4773+
pub fn claim_funds_with_known_custom_tlvs(&self, payment_preimage: PaymentPreimage) {
4774+
self.claim_payment_internal(payment_preimage, true);
4775+
}
4776+
4777+
fn claim_payment_internal(&self, payment_preimage: PaymentPreimage, custom_tlvs_known: bool) {
47564778
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
47574779

47584780
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
@@ -4779,6 +4801,23 @@ where
47794801
log_error!(self.logger, "Got a duplicate pending claimable event on payment hash {}! Please report this bug",
47804802
log_bytes!(payment_hash.0));
47814803
}
4804+
4805+
if let Some(RecipientOnionFields { ref custom_tlvs, .. }) = payment.onion_fields {
4806+
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
4807+
log_info!(self.logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
4808+
log_bytes!(payment_hash.0), log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
4809+
claimable_payments.pending_claiming_payments.remove(&payment_hash);
4810+
mem::drop(claimable_payments);
4811+
for htlc in payment.htlcs {
4812+
let reason = self.get_htlc_fail_reason_from_failure_code(FailureCode::InvalidOnionPayload(None), &htlc);
4813+
let source = HTLCSource::PreviousHopData(htlc.prev_hop);
4814+
let receiver = HTLCDestination::FailedPayment { payment_hash };
4815+
self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
4816+
}
4817+
return;
4818+
}
4819+
}
4820+
47824821
payment.htlcs
47834822
} else { return; }
47844823
};

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
@@ -3328,12 +3328,20 @@ fn claim_from_closed_chan() {
33283328
}
33293329

33303330
#[test]
3331-
fn test_custom_tlvs() {
3332-
do_test_custom_tlvs(true);
3333-
do_test_custom_tlvs(false);
3331+
fn test_custom_tlvs_basic() {
3332+
do_test_custom_tlvs(false, false, false);
3333+
do_test_custom_tlvs(true, false, false);
33343334
}
33353335

3336-
fn do_test_custom_tlvs(spontaneous: bool) {
3336+
#[test]
3337+
fn test_custom_tlvs_explicit_claim() {
3338+
// Test that when receiving even custom TLVs the user must explicitly accept in case they
3339+
// are unknown.
3340+
do_test_custom_tlvs(false, true, false);
3341+
do_test_custom_tlvs(false, true, true);
3342+
}
3343+
3344+
fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) {
33373345
let chanmon_cfgs = create_chanmon_cfgs(2);
33383346
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
33393347
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None; 2]);
@@ -3345,7 +3353,7 @@ fn do_test_custom_tlvs(spontaneous: bool) {
33453353
let (mut route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat);
33463354
let payment_id = PaymentId(our_payment_hash.0);
33473355
let custom_tlvs = vec![
3348-
(5482373483, vec![1, 2, 3, 4]),
3356+
(if even_tlvs { 5482373482 } else { 5482373483 }, vec![1, 2, 3, 4]),
33493357
(5482373487, vec![0x42u8; 16]),
33503358
];
33513359
let onion_fields = RecipientOnionFields {
@@ -3388,7 +3396,22 @@ fn do_test_custom_tlvs(spontaneous: bool) {
33883396
_ => panic!("Unexpected event"),
33893397
}
33903398

3391-
claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
3399+
match (known_tlvs, even_tlvs) {
3400+
(true, _) => {
3401+
nodes[1].node.claim_funds_with_known_custom_tlvs(our_payment_preimage);
3402+
let expected_total_fee_msat = pass_claimed_payment_along_route(&nodes[0], &[&[&nodes[1]]], &[0; 1], false, our_payment_preimage);
3403+
expect_payment_sent!(&nodes[0], our_payment_preimage, Some(expected_total_fee_msat));
3404+
},
3405+
(false, false) => {
3406+
claim_payment(&nodes[0], &[&nodes[1]], our_payment_preimage);
3407+
},
3408+
(false, true) => {
3409+
nodes[1].node.claim_funds(our_payment_preimage);
3410+
let expected_destinations = vec![HTLCDestination::FailedPayment { payment_hash: our_payment_hash }];
3411+
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], expected_destinations);
3412+
pass_failed_payment_back(&nodes[0], &[&[&nodes[1]]], false, our_payment_hash, PaymentFailureReason::RecipientRejected);
3413+
}
3414+
}
33923415
}
33933416

33943417
#[test]

0 commit comments

Comments
 (0)