Skip to content

Commit 4822ab5

Browse files
committed
ln: introduce LocalHTLCFailureReason representing BOLT04
Introduce an enum representation of BOLT04 error codes that will be introduced in the commits that follow, along with being extended to represent failures that are otherwise erased by BOLT04 error codes (insufficient liquidity which is erased by temporary channel failure, for example).
1 parent b76dbdd commit 4822ab5

File tree

1 file changed

+182
-5
lines changed

1 file changed

+182
-5
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 182 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,11 +1069,6 @@ where
10691069
let mut is_from_final_non_blinded_node = false;
10701070
let mut hop_hold_times: Vec<u32> = Vec::new();
10711071

1072-
const BADONION: u16 = 0x8000;
1073-
const PERM: u16 = 0x4000;
1074-
const NODE: u16 = 0x2000;
1075-
const UPDATE: u16 = 0x1000;
1076-
10771072
enum ErrorHop<'a> {
10781073
RouteHop(&'a RouteHop),
10791074
TrampolineHop(&'a TrampolineHop),
@@ -1451,6 +1446,188 @@ where
14511446
}
14521447
}
14531448

1449+
const BADONION: u16 = 0x8000;
1450+
const PERM: u16 = 0x4000;
1451+
const NODE: u16 = 0x2000;
1452+
const UPDATE: u16 = 0x1000;
1453+
1454+
/// The reason that a HTLC was failed by the local node. These errors represent direct,
1455+
/// human-readable mappings of BOLT04 error codes.
1456+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1457+
pub enum LocalHTLCFailureReason {
1458+
/// There has been a temporary processing failure on the node which may resolve on retry.
1459+
TemporaryNodeFailure,
1460+
/// These has been a permanent processing failure on the node which will not resolve on retry.
1461+
PermanentNodeFailure,
1462+
/// The HTLC does not implement a feature that is required by our node.
1463+
///
1464+
/// The sender may have outdated gossip, or a bug in its implementation.
1465+
RequiredNodeFeature,
1466+
/// The onion version specified by the HTLC packet is unknown to our node.
1467+
InvalidOnionVersion,
1468+
/// The integrity of the HTLC packet cannot be verified because it has an invalid HMAC.
1469+
InvalidOnionHMAC,
1470+
/// The onion packet has an invalid ephemeral key, so the HTLC cannot be processed.
1471+
InvalidOnionKey,
1472+
/// A temporary forwarding error has occurred which may resolve on retry.
1473+
TemporaryChannelFailure,
1474+
/// A permanent forwarding error has occurred which will not resolve on retry.
1475+
PermanentChannelFailure,
1476+
/// The HTLC does not implement a feature that is required by our channel for processing.
1477+
RequiredChannelFeature,
1478+
/// The HTLC's target outgoing channel that is not known to our node.
1479+
UnknownNextPeer,
1480+
/// The HTLC amount is below our advertised htlc_minimum_msat.
1481+
///
1482+
/// The sender may have outdated gossip, or a bug in its implementation.
1483+
AmountBelowMinimum,
1484+
/// The HTLC does not pay sufficient fees.
1485+
///
1486+
/// The sender may have outdated gossip, or a bug in its implementation.
1487+
FeeInsufficient,
1488+
/// The HTLC does not meet the cltv_expiry_delta advertised by our node, set by
1489+
/// [`ChannelConfig::cltv_expiry_delta`].
1490+
///
1491+
/// The sender may have outdated gossip, or a bug in its implementation.
1492+
///
1493+
/// [`ChannelConfig::cltv_expiry_delta`]: crate::util::config::ChannelConfig::cltv_expiry_delta
1494+
IncorrectCLTVExpiry,
1495+
/// The HTLC expires too close to the current block height to be safely processed.
1496+
CLTVExpiryTooSoon,
1497+
/// A payment was made to our node that either had incorrect payment information, or was
1498+
/// unknown to us.
1499+
IncorrectPaymentDetails,
1500+
/// The HTLC's expiry is less than the expiry height specified by the sender.
1501+
///
1502+
/// The forwarding node has either tampered with this value, or the sending node has an
1503+
/// old best block height.
1504+
FinalIncorrectCLTVExpiry,
1505+
/// The HTLC's amount is less than the amount specified by the sender.
1506+
///
1507+
/// The forwarding node has tampered with this value, or has a bug in its implementation.
1508+
FinalIncorrectHTLCAmount,
1509+
/// The channel has been marked as disabled because the channel peer is offline.
1510+
ChannelDisabled,
1511+
/// The HTLC expires too far in the future, so it is rejected to avoid the worst-case outcome
1512+
/// of funds being held for extended periods of time.
1513+
///
1514+
/// Limit set by ['crate::ln::channelmanager::CLTV_FAR_FAR_AWAY`].
1515+
CLTVExpiryTooFar,
1516+
/// The HTLC payload contained in the onion packet could not be understood by our node.
1517+
InvalidOnionPayload,
1518+
/// The total amount for a multi-part payment did not arrive in time, so the HTLCs partially
1519+
/// paying the amount were canceled.
1520+
MPPTimeout,
1521+
/// Our node was selected as part of a blinded path, but the packet we received was not
1522+
/// properly constructed, or had incorrect values for the blinded path.
1523+
///
1524+
/// This may happen if the forwarding node tamperd with the HTLC or the sender or recipient
1525+
/// implementations have a bug.
1526+
InvalidOnionBlinding,
1527+
/// UnknownFailureCode represents BOLT04 failure codes that we are not familiar with. We will
1528+
/// encounter this if:
1529+
/// - A peer sends us a new failure code that LDK has not yet been upgraded to understand.
1530+
/// - We read a deprecated failure code from disk that LDK no longer uses.
1531+
///
1532+
/// See <https://github.com/lightning/bolts/blob/master/04-onion-routing.md#returning-errors>
1533+
/// for latest defined error codes.
1534+
UnknownFailureCode {
1535+
/// The bolt 04 failure code.
1536+
code: u16,
1537+
},
1538+
}
1539+
1540+
impl LocalHTLCFailureReason {
1541+
pub(super) fn failure_code(&self) -> u16 {
1542+
match self {
1543+
Self::TemporaryNodeFailure => NODE | 2,
1544+
Self::PermanentNodeFailure => PERM | NODE | 2,
1545+
Self::RequiredNodeFeature => PERM | NODE | 3,
1546+
Self::InvalidOnionVersion => BADONION | PERM | 4,
1547+
Self::InvalidOnionHMAC => BADONION | PERM | 5,
1548+
Self::InvalidOnionKey => BADONION | PERM | 6,
1549+
Self::TemporaryChannelFailure => UPDATE | 7,
1550+
Self::PermanentChannelFailure => PERM | 8,
1551+
Self::RequiredChannelFeature => PERM | 9,
1552+
Self::UnknownNextPeer => PERM | 10,
1553+
Self::AmountBelowMinimum => UPDATE | 11,
1554+
Self::FeeInsufficient => UPDATE | 12,
1555+
Self::IncorrectCLTVExpiry => UPDATE | 13,
1556+
Self::CLTVExpiryTooSoon => UPDATE | 14,
1557+
Self::IncorrectPaymentDetails => PERM | 15,
1558+
Self::FinalIncorrectCLTVExpiry => 18,
1559+
Self::FinalIncorrectHTLCAmount => 19,
1560+
Self::ChannelDisabled => UPDATE | 20,
1561+
Self::CLTVExpiryTooFar => 21,
1562+
Self::InvalidOnionPayload => PERM | 22,
1563+
Self::MPPTimeout => 23,
1564+
Self::InvalidOnionBlinding => BADONION | PERM | 24,
1565+
Self::UnknownFailureCode { code } => *code,
1566+
}
1567+
}
1568+
1569+
pub(super) fn is_temporary(&self) -> bool {
1570+
self.failure_code() & UPDATE == UPDATE
1571+
}
1572+
1573+
#[cfg(test)]
1574+
pub(super) fn is_permanent(&self) -> bool {
1575+
self.failure_code() & PERM == PERM
1576+
}
1577+
}
1578+
1579+
impl From<u16> for LocalHTLCFailureReason {
1580+
fn from(value: u16) -> Self {
1581+
if value == (NODE | 2) {
1582+
LocalHTLCFailureReason::TemporaryNodeFailure
1583+
} else if value == (PERM | NODE | 2) {
1584+
LocalHTLCFailureReason::PermanentNodeFailure
1585+
} else if value == (PERM | NODE | 3) {
1586+
LocalHTLCFailureReason::RequiredNodeFeature
1587+
} else if value == (BADONION | PERM | 4) {
1588+
LocalHTLCFailureReason::InvalidOnionVersion
1589+
} else if value == (BADONION | PERM | 5) {
1590+
LocalHTLCFailureReason::InvalidOnionHMAC
1591+
} else if value == (BADONION | PERM | 6) {
1592+
LocalHTLCFailureReason::InvalidOnionKey
1593+
} else if value == (UPDATE | 7) {
1594+
LocalHTLCFailureReason::TemporaryChannelFailure
1595+
} else if value == (PERM | 8) {
1596+
LocalHTLCFailureReason::PermanentChannelFailure
1597+
} else if value == (PERM | 9) {
1598+
LocalHTLCFailureReason::RequiredChannelFeature
1599+
} else if value == (PERM | 10) {
1600+
LocalHTLCFailureReason::UnknownNextPeer
1601+
} else if value == (UPDATE | 11) {
1602+
LocalHTLCFailureReason::AmountBelowMinimum
1603+
} else if value == (UPDATE | 12) {
1604+
LocalHTLCFailureReason::FeeInsufficient
1605+
} else if value == (UPDATE | 13) {
1606+
LocalHTLCFailureReason::IncorrectCLTVExpiry
1607+
} else if value == (UPDATE | 14) {
1608+
LocalHTLCFailureReason::CLTVExpiryTooSoon
1609+
} else if value == (PERM | 15) {
1610+
LocalHTLCFailureReason::IncorrectPaymentDetails
1611+
} else if value == 18 {
1612+
LocalHTLCFailureReason::FinalIncorrectCLTVExpiry
1613+
} else if value == 19 {
1614+
LocalHTLCFailureReason::FinalIncorrectHTLCAmount
1615+
} else if value == (UPDATE | 20) {
1616+
LocalHTLCFailureReason::ChannelDisabled
1617+
} else if value == 21 {
1618+
LocalHTLCFailureReason::CLTVExpiryTooFar
1619+
} else if value == (PERM | 22) {
1620+
LocalHTLCFailureReason::InvalidOnionPayload
1621+
} else if value == 23 {
1622+
LocalHTLCFailureReason::MPPTimeout
1623+
} else if value == (BADONION | PERM | 24) {
1624+
LocalHTLCFailureReason::InvalidOnionBlinding
1625+
} else {
1626+
LocalHTLCFailureReason::UnknownFailureCode { code: value }
1627+
}
1628+
}
1629+
}
1630+
14541631
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
14551632
#[cfg_attr(test, derive(PartialEq))]
14561633
pub(super) struct HTLCFailReason(HTLCFailReasonRepr);

0 commit comments

Comments
 (0)