Skip to content

Commit 05789d4

Browse files
committed
Add FailureCode::InvalidOnionPayload variant
When a user decodes custom TLVs, if they fail to recognize even type numbers they should fail back with the correct failure code and fail data. This new variant adds the proper failure variant for the user to pass into `ChannelManager::fail_htlc_backwards_with_reason`. Note that the enum discriminants were removed because when adding a struct variant we can no longer make use of the discriminant through casting like we previously did, and instead have to manually define the associated failure code anyway.
1 parent 39947b8 commit 05789d4

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

lightning/src/ln/channelmanager.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -359,15 +359,32 @@ struct ReceiveError {
359359
pub enum FailureCode {
360360
/// We had a temporary error processing the payment. Useful if no other error codes fit
361361
/// and you want to indicate that the payer may want to retry.
362-
TemporaryNodeFailure = 0x2000 | 2,
362+
TemporaryNodeFailure,
363363
/// We have a required feature which was not in this onion. For example, you may require
364364
/// some additional metadata that was not provided with this payment.
365-
RequiredNodeFeatureMissing = 0x4000 | 0x2000 | 3,
365+
RequiredNodeFeatureMissing,
366366
/// You may wish to use this when a `payment_preimage` is unknown, or the CLTV expiry of
367367
/// the HTLC is too close to the current block height for safe handling.
368368
/// Using this failure code in [`ChannelManager::fail_htlc_backwards_with_reason`] is
369369
/// equivalent to calling [`ChannelManager::fail_htlc_backwards`].
370-
IncorrectOrUnknownPaymentDetails = 0x4000 | 15,
370+
IncorrectOrUnknownPaymentDetails,
371+
/// We failed to process the payload after the onion was decrypted. You may wish to
372+
/// use this when receiving custom HTLC TLVs with even type numbers that you don't recognize.
373+
///
374+
/// If available, the tuple data may include the type number and byte offset in the
375+
/// decrypted byte stream where the failure occurred.
376+
InvalidOnionPayload(Option<(u64, u16)>),
377+
}
378+
379+
impl Into<u16> for FailureCode {
380+
fn into(self) -> u16 {
381+
match self {
382+
FailureCode::TemporaryNodeFailure => 0x2000 | 2,
383+
FailureCode::RequiredNodeFeatureMissing => 0x4000 | 0x2000 | 3,
384+
FailureCode::IncorrectOrUnknownPaymentDetails => 0x4000 | 15,
385+
FailureCode::InvalidOnionPayload(_) => 0x4000 | 22,
386+
}
387+
}
371388
}
372389

373390
/// Error type returned across the peer_state mutex boundary. When an Err is generated for a
@@ -4570,12 +4587,19 @@ where
45704587
/// Gets error data to form an [`HTLCFailReason`] given a [`FailureCode`] and [`ClaimableHTLC`].
45714588
fn get_htlc_fail_reason_from_failure_code(&self, failure_code: FailureCode, htlc: &ClaimableHTLC) -> HTLCFailReason {
45724589
match failure_code {
4573-
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code as u16),
4574-
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code as u16),
4590+
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code.into()),
4591+
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code.into()),
45754592
FailureCode::IncorrectOrUnknownPaymentDetails => {
45764593
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
45774594
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
4578-
HTLCFailReason::reason(failure_code as u16, htlc_msat_height_data)
4595+
HTLCFailReason::reason(failure_code.into(), htlc_msat_height_data)
4596+
},
4597+
FailureCode::InvalidOnionPayload(data) => {
4598+
let fail_data = match data {
4599+
Some((typ, offset)) => [BigSize(typ).encode(), offset.encode()].concat(),
4600+
None => Vec::new(),
4601+
};
4602+
HTLCFailReason::reason(failure_code.into(), fail_data)
45794603
}
45804604
}
45814605
}

lightning/src/ln/onion_route_tests.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::ln::features::{InitFeatures, Bolt11InvoiceFeatures};
2424
use crate::ln::msgs;
2525
use crate::ln::msgs::{ChannelMessageHandler, ChannelUpdate};
2626
use crate::ln::wire::Encode;
27-
use crate::util::ser::{Writeable, Writer};
27+
use crate::util::ser::{Writeable, Writer, BigSize};
2828
use crate::util::test_utils;
2929
use crate::util::config::{UserConfig, ChannelConfig, MaxDustHTLCExposure};
3030
use crate::util::errors::APIError;
@@ -942,10 +942,16 @@ fn do_test_fail_htlc_backwards_with_reason(failure_code: FailureCode) {
942942
let mut htlc_msat_height_data = (payment_amount as u64).to_be_bytes().to_vec();
943943
htlc_msat_height_data.extend_from_slice(&CHAN_CONFIRM_DEPTH.to_be_bytes());
944944
htlc_msat_height_data
945+
},
946+
FailureCode::InvalidOnionPayload(data) => {
947+
match data {
948+
Some((typ, offset)) => [BigSize(typ).encode(), offset.encode()].concat(),
949+
None => Vec::new(),
950+
}
945951
}
946952
};
947953

948-
let failure_code = failure_code as u16;
954+
let failure_code = failure_code.into();
949955
let permanent_flag = 0x4000;
950956
let permanent_fail = (failure_code & permanent_flag) != 0;
951957
expect_payment_failed!(nodes[0], payment_hash, permanent_fail, failure_code, failure_data);
@@ -957,6 +963,8 @@ fn test_fail_htlc_backwards_with_reason() {
957963
do_test_fail_htlc_backwards_with_reason(FailureCode::TemporaryNodeFailure);
958964
do_test_fail_htlc_backwards_with_reason(FailureCode::RequiredNodeFeatureMissing);
959965
do_test_fail_htlc_backwards_with_reason(FailureCode::IncorrectOrUnknownPaymentDetails);
966+
do_test_fail_htlc_backwards_with_reason(FailureCode::InvalidOnionPayload(Some((1 << 16, 42))));
967+
do_test_fail_htlc_backwards_with_reason(FailureCode::InvalidOnionPayload(None));
960968
}
961969

962970
macro_rules! get_phantom_route {

0 commit comments

Comments
 (0)