Skip to content

Commit 9e66ceb

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 d083c04 commit 9e66ceb

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
@@ -352,15 +352,32 @@ struct ReceiveError {
352352
pub enum FailureCode {
353353
/// We had a temporary error processing the payment. Useful if no other error codes fit
354354
/// and you want to indicate that the payer may want to retry.
355-
TemporaryNodeFailure = 0x2000 | 2,
355+
TemporaryNodeFailure,
356356
/// We have a required feature which was not in this onion. For example, you may require
357357
/// some additional metadata that was not provided with this payment.
358-
RequiredNodeFeatureMissing = 0x4000 | 0x2000 | 3,
358+
RequiredNodeFeatureMissing,
359359
/// You may wish to use this when a `payment_preimage` is unknown, or the CLTV expiry of
360360
/// the HTLC is too close to the current block height for safe handling.
361361
/// Using this failure code in [`ChannelManager::fail_htlc_backwards_with_reason`] is
362362
/// equivalent to calling [`ChannelManager::fail_htlc_backwards`].
363-
IncorrectOrUnknownPaymentDetails = 0x4000 | 15,
363+
IncorrectOrUnknownPaymentDetails,
364+
/// We failed to process the payload after the onion was decrypted. You may wish to
365+
/// use this when receiving custom HTLC TLVs with even type numbers that you don't recognize.
366+
///
367+
/// The tuple data should include the type number and byte offset in the decrypted byte stream
368+
/// where the failure occurred.
369+
InvalidOnionPayload(Option<(u64, u16)>),
370+
}
371+
372+
impl Into<u16> for FailureCode {
373+
fn into(self) -> u16 {
374+
match self {
375+
FailureCode::TemporaryNodeFailure => 0x2000 | 2,
376+
FailureCode::RequiredNodeFeatureMissing => 0x4000 | 0x2000 | 3,
377+
FailureCode::IncorrectOrUnknownPaymentDetails => 0x4000 | 15,
378+
FailureCode::InvalidOnionPayload(_) => 0x4000 | 22,
379+
}
380+
}
364381
}
365382

366383
/// Error type returned across the peer_state mutex boundary. When an Err is generated for a
@@ -4212,12 +4229,19 @@ where
42124229
/// Gets error data to form an [`HTLCFailReason`] given a [`FailureCode`] and [`ClaimableHTLC`].
42134230
fn get_htlc_fail_reason_from_failure_code(&self, failure_code: FailureCode, htlc: &ClaimableHTLC) -> HTLCFailReason {
42144231
match failure_code {
4215-
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code as u16),
4216-
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code as u16),
4232+
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code.into()),
4233+
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code.into()),
42174234
FailureCode::IncorrectOrUnknownPaymentDetails => {
42184235
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
42194236
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
4220-
HTLCFailReason::reason(failure_code as u16, htlc_msat_height_data)
4237+
HTLCFailReason::reason(failure_code.into(), htlc_msat_height_data)
4238+
},
4239+
FailureCode::InvalidOnionPayload(data) => {
4240+
let fail_data = match data {
4241+
Some((typ, offset)) => [BigSize(typ).encode(), offset.encode()].concat(),
4242+
None => Vec::new(),
4243+
};
4244+
HTLCFailReason::reason(failure_code.into(), fail_data)
42214245
}
42224246
}
42234247
}

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, InvoiceFeatures};
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};
3030
use crate::util::errors::APIError;
@@ -941,10 +941,16 @@ fn do_test_fail_htlc_backwards_with_reason(failure_code: FailureCode) {
941941
let mut htlc_msat_height_data = (payment_amount as u64).to_be_bytes().to_vec();
942942
htlc_msat_height_data.extend_from_slice(&CHAN_CONFIRM_DEPTH.to_be_bytes());
943943
htlc_msat_height_data
944+
},
945+
FailureCode::InvalidOnionPayload(data) => {
946+
match data {
947+
Some((typ, offset)) => [BigSize(typ).encode(), offset.encode()].concat(),
948+
None => Vec::new(),
949+
}
944950
}
945951
};
946952

947-
let failure_code = failure_code as u16;
953+
let failure_code = failure_code.into();
948954
let permanent_flag = 0x4000;
949955
let permanent_fail = (failure_code & permanent_flag) != 0;
950956
expect_payment_failed!(nodes[0], payment_hash, permanent_fail, failure_code, failure_data);
@@ -956,6 +962,8 @@ fn test_fail_htlc_backwards_with_reason() {
956962
do_test_fail_htlc_backwards_with_reason(FailureCode::TemporaryNodeFailure);
957963
do_test_fail_htlc_backwards_with_reason(FailureCode::RequiredNodeFeatureMissing);
958964
do_test_fail_htlc_backwards_with_reason(FailureCode::IncorrectOrUnknownPaymentDetails);
965+
do_test_fail_htlc_backwards_with_reason(FailureCode::InvalidOnionPayload(Some((1 << 16, 42))));
966+
do_test_fail_htlc_backwards_with_reason(FailureCode::InvalidOnionPayload(None));
959967
}
960968

961969
macro_rules! get_phantom_route {

0 commit comments

Comments
 (0)