Skip to content

Commit 21a8b75

Browse files
committed
Add forwards-compatibility logic in LocalHTLCFailureReason ser
We recently created a `LocalHTLCFailureReason` enum to cover detailed reasons why an HTLC may have failed, in excess of the on-the-wire failure encoding. Sadly, when we did so we introduced a serialization format which isn't particularly conducive to introducing new failure reasons in the future. Luckily, `LocalHTLCFailureReason` already has logic that works for forwards-compatibility - it can be converted to, and from, the on-the-wire error codes. Thus, here, we take advantage of that, writing both the on-the-wire error code as well as a code for the specific case. If we don't recognize the specific case on deserialization, we'll fall back to the default case for the on-the-wire code we've written. We also, of course, include a length-prefixed TLV stream to allow for additional fields in the future. Fixes #4087
1 parent 1ed6c4b commit 21a8b75

File tree

1 file changed

+71
-46
lines changed

1 file changed

+71
-46
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::crypto::streams::ChaChaReader;
1414
use crate::events::HTLCHandlingFailureReason;
1515
use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
1616
use crate::ln::channelmanager::{HTLCSource, RecipientOnionFields};
17-
use crate::ln::msgs;
17+
use crate::ln::msgs::{self, DecodeError};
1818
use crate::offers::invoice_request::InvoiceRequest;
1919
use crate::routing::gossip::NetworkUpdate;
2020
use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters, TrampolineHop};
@@ -1807,51 +1807,76 @@ impl_from_u16_for_htlc_reason!(
18071807
]
18081808
);
18091809

1810-
impl_writeable_tlv_based_enum!(LocalHTLCFailureReason,
1811-
(1, TemporaryNodeFailure) => {},
1812-
(3, PermanentNodeFailure) => {},
1813-
(5, RequiredNodeFeature) => {},
1814-
(7, InvalidOnionVersion) => {},
1815-
(9, InvalidOnionHMAC) => {},
1816-
(11, InvalidOnionKey) => {},
1817-
(13, TemporaryChannelFailure) => {},
1818-
(15, PermanentChannelFailure) => {},
1819-
(17, RequiredChannelFeature) => {},
1820-
(19, UnknownNextPeer) => {},
1821-
(21, AmountBelowMinimum) => {},
1822-
(23, FeeInsufficient) => {},
1823-
(25, IncorrectCLTVExpiry) => {},
1824-
(27, CLTVExpiryTooSoon) => {},
1825-
(29, IncorrectPaymentDetails) => {},
1826-
(31, FinalIncorrectCLTVExpiry) => {},
1827-
(33, FinalIncorrectHTLCAmount) => {},
1828-
(35, ChannelDisabled) => {},
1829-
(37, CLTVExpiryTooFar) => {},
1830-
(39, InvalidOnionPayload) => {},
1831-
(41, MPPTimeout) => {},
1832-
(43, InvalidOnionBlinding) => {},
1833-
(45, UnknownFailureCode) => {
1834-
(0, code, required),
1835-
},
1836-
(47, ForwardExpiryBuffer) => {},
1837-
(49, InvalidTrampolineForward) => {},
1838-
(51, PaymentClaimBuffer) => {},
1839-
(53, DustLimitHolder) => {},
1840-
(55, DustLimitCounterparty) => {},
1841-
(57, FeeSpikeBuffer) => {},
1842-
(59, PrivateChannelForward) => {},
1843-
(61, RealSCIDForward) => {},
1844-
(63, ChannelNotReady) => {},
1845-
(65, InvalidKeysendPreimage) => {},
1846-
(67, InvalidTrampolinePayload) => {},
1847-
(69, PaymentSecretRequired) => {},
1848-
(71, OutgoingCLTVTooSoon) => {},
1849-
(73, ChannelClosed) => {},
1850-
(75, OnChainTimeout) => {},
1851-
(77, ZeroAmount) => {},
1852-
(79, HTLCMinimum) => {},
1853-
(81, HTLCMaximum) => {},
1854-
(83, PeerOffline) => {},
1810+
macro_rules! ser_failure_reasons {
1811+
($(($idx: expr, $name: ident)),*) => {
1812+
impl Readable for LocalHTLCFailureReason {
1813+
fn read<R: Read>(r: &mut R) -> Result<LocalHTLCFailureReason, DecodeError> {
1814+
let code: u16 = Readable::read(r)?;
1815+
let reason: u8 = Readable::read(r)?;
1816+
read_tlv_fields!(r, {});
1817+
match reason {
1818+
$($idx => Ok(LocalHTLCFailureReason::$name),)*
1819+
_ => Ok(code.into()),
1820+
}
1821+
}
1822+
}
1823+
impl Writeable for LocalHTLCFailureReason {
1824+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), bitcoin::io::Error> {
1825+
self.failure_code().write(writer)?;
1826+
let reason: u8 = match self {
1827+
$(LocalHTLCFailureReason::$name => $idx,)*
1828+
LocalHTLCFailureReason::UnknownFailureCode { .. } => 0xff,
1829+
};
1830+
reason.write(writer)?;
1831+
write_tlv_fields!(writer, {});
1832+
Ok(())
1833+
}
1834+
}
1835+
}
1836+
}
1837+
1838+
ser_failure_reasons!(
1839+
(1, TemporaryNodeFailure),
1840+
(2, PermanentNodeFailure),
1841+
(3, RequiredNodeFeature),
1842+
(4, InvalidOnionVersion),
1843+
(5, InvalidOnionHMAC),
1844+
(6, InvalidOnionKey),
1845+
(7, TemporaryChannelFailure),
1846+
(8, PermanentChannelFailure),
1847+
(9, RequiredChannelFeature),
1848+
(10, UnknownNextPeer),
1849+
(11, AmountBelowMinimum),
1850+
(12, FeeInsufficient),
1851+
(13, IncorrectCLTVExpiry),
1852+
(14, CLTVExpiryTooSoon),
1853+
(15, IncorrectPaymentDetails),
1854+
(16, FinalIncorrectCLTVExpiry),
1855+
(17, FinalIncorrectHTLCAmount),
1856+
(18, ChannelDisabled),
1857+
(19, CLTVExpiryTooFar),
1858+
(20, InvalidOnionPayload),
1859+
(21, MPPTimeout),
1860+
(22, InvalidOnionBlinding),
1861+
(23, ForwardExpiryBuffer),
1862+
(24, InvalidTrampolineForward),
1863+
(25, PaymentClaimBuffer),
1864+
(26, DustLimitHolder),
1865+
(27, DustLimitCounterparty),
1866+
(28, FeeSpikeBuffer),
1867+
(29, PrivateChannelForward),
1868+
(30, RealSCIDForward),
1869+
(31, ChannelNotReady),
1870+
(32, InvalidKeysendPreimage),
1871+
(33, InvalidTrampolinePayload),
1872+
(34, PaymentSecretRequired),
1873+
(35, OutgoingCLTVTooSoon),
1874+
(36, ChannelClosed),
1875+
(37, OnChainTimeout),
1876+
(38, ZeroAmount),
1877+
(39, HTLCMinimum),
1878+
(40, HTLCMaximum),
1879+
(41, PeerOffline)
18551880
);
18561881

18571882
impl From<&HTLCFailReason> for HTLCHandlingFailureReason {

0 commit comments

Comments
 (0)