Skip to content

Commit 3e3c547

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 5ee097f commit 3e3c547

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,19 +346,37 @@ struct ReceiveError {
346346
/// using [`ChannelManager::fail_htlc_backwards_with_reason`].
347347
///
348348
/// For more info on failure codes, see <https://github.com/lightning/bolts/blob/master/04-onion-routing.md#failure-messages>.
349+
#[repr(u16)]
349350
#[derive(Clone, Copy)]
350351
pub enum FailureCode {
351352
/// We had a temporary error processing the payment. Useful if no other error codes fit
352353
/// and you want to indicate that the payer may want to retry.
353-
TemporaryNodeFailure = 0x2000 | 2,
354+
TemporaryNodeFailure,
354355
/// We have a required feature which was not in this onion. For example, you may require
355356
/// some additional metadata that was not provided with this payment.
356-
RequiredNodeFeatureMissing = 0x4000 | 0x2000 | 3,
357+
RequiredNodeFeatureMissing,
357358
/// You may wish to use this when a `payment_preimage` is unknown, or the CLTV expiry of
358359
/// the HTLC is too close to the current block height for safe handling.
359360
/// Using this failure code in [`ChannelManager::fail_htlc_backwards_with_reason`] is
360361
/// equivalent to calling [`ChannelManager::fail_htlc_backwards`].
361-
IncorrectOrUnknownPaymentDetails = 0x4000 | 15,
362+
IncorrectOrUnknownPaymentDetails,
363+
/// We failed to process the payload after the onion was decrypted. You may wish to
364+
/// use this when receiving custom HTLC TLVs with even type numbers that you don't recognize.
365+
///
366+
/// The tuple data should include the type number and byte offset in the decrypted byte stream
367+
/// where the failure occurred.
368+
InvalidOnionPayload(Option<(u64, u16)>),
369+
}
370+
371+
impl Into<u16> for FailureCode {
372+
fn into(self) -> u16 {
373+
match self {
374+
FailureCode::TemporaryNodeFailure => 0x2000 | 2,
375+
FailureCode::RequiredNodeFeatureMissing => 0x4000 | 0x2000 | 3,
376+
FailureCode::IncorrectOrUnknownPaymentDetails => 0x4000 | 15,
377+
FailureCode::InvalidOnionPayload(_) => 0x4000 | 22,
378+
}
379+
}
362380
}
363381

364382
type ShutdownResult = (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>);
@@ -4049,12 +4067,19 @@ where
40494067
/// Gets error data to form an [`HTLCFailReason`] given a [`FailureCode`] and [`ClaimableHTLC`].
40504068
fn get_htlc_fail_reason_from_failure_code(&self, failure_code: FailureCode, htlc: &ClaimableHTLC) -> HTLCFailReason {
40514069
match failure_code {
4052-
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code as u16),
4053-
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code as u16),
4070+
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(failure_code.into()),
4071+
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(failure_code.into()),
40544072
FailureCode::IncorrectOrUnknownPaymentDetails => {
40554073
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
40564074
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
4057-
HTLCFailReason::reason(failure_code as u16, htlc_msat_height_data)
4075+
HTLCFailReason::reason(failure_code.into(), htlc_msat_height_data)
4076+
},
4077+
FailureCode::InvalidOnionPayload(data) => {
4078+
let fail_data = match data {
4079+
Some((typ, offset)) => [BigSize(typ).encode(), offset.encode()].concat(),
4080+
None => Vec::new(),
4081+
};
4082+
HTLCFailReason::reason(failure_code.into(), fail_data)
40584083
}
40594084
}
40604085
}

lightning/src/ln/onion_route_tests.rs

Lines changed: 10 additions & 2 deletions
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)