From dabae73d0a1760fed6b28f0cd1b0ae89bc0409e3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 1 Dec 2022 19:20:19 +0000 Subject: [PATCH] Move `HTLCFailReason` to `onion_utils` Now that it's entirely abstracted, there's no reason for `HTLCFailReason` to be in `channelmanager`, it's really an onion-level abstraction. --- lightning/src/ln/channel.rs | 3 +- lightning/src/ln/channelmanager.rs | 87 +----------------------------- lightning/src/ln/onion_utils.rs | 86 +++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 87 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 5cc4f4a364b..9f47bacc74d 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -27,9 +27,10 @@ use crate::ln::features::{ChannelTypeFeatures, InitFeatures}; use crate::ln::msgs; use crate::ln::msgs::{DecodeError, OptionalField, DataLossProtect}; use crate::ln::script::{self, ShutdownScript}; -use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; +use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; use crate::ln::chan_utils; +use crate::ln::onion_utils::HTLCFailReason; use crate::chain::BestBlock; use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS}; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index eddb5589e4f..7fed7b2f427 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -49,6 +49,7 @@ use crate::ln::features::InvoiceFeatures; use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteHop, RoutePath, RouteParameters}; use crate::ln::msgs; use crate::ln::onion_utils; +use crate::ln::onion_utils::HTLCFailReason; use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT}; use crate::ln::wire::Encode; use crate::chain::keysinterface::{Sign, KeysInterface, KeysManager, Recipient}; @@ -276,82 +277,6 @@ impl HTLCSource { } } -#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug -pub(super) enum HTLCFailReason { - LightningError { - err: msgs::OnionErrorPacket, - }, - Reason { - failure_code: u16, - data: Vec, - } -} - -impl core::fmt::Debug for HTLCFailReason { - fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { - match self { - HTLCFailReason::Reason { ref failure_code, .. } => { - write!(f, "HTLC error code {}", failure_code) - }, - HTLCFailReason::LightningError { .. } => { - write!(f, "pre-built LightningError") - } - } - } -} - -impl HTLCFailReason { - pub(super) fn reason(failure_code: u16, data: Vec) -> Self { - Self::Reason { failure_code, data } - } - - pub(super) fn from_failure_code(failure_code: u16) -> Self { - Self::Reason { failure_code, data: Vec::new() } - } - - pub(super) fn from_msg(msg: &msgs::UpdateFailHTLC) -> Self { - Self::LightningError { err: msg.reason.clone() } - } - - fn get_encrypted_failure_packet(&self, incoming_packet_shared_secret: &[u8; 32], phantom_shared_secret: &Option<[u8; 32]>) -> msgs::OnionErrorPacket { - match self { - HTLCFailReason::Reason { ref failure_code, ref data } => { - if let Some(phantom_ss) = phantom_shared_secret { - let phantom_packet = onion_utils::build_failure_packet(phantom_ss, *failure_code, &data[..]).encode(); - let encrypted_phantom_packet = onion_utils::encrypt_failure_packet(phantom_ss, &phantom_packet); - onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &encrypted_phantom_packet.data[..]) - } else { - let packet = onion_utils::build_failure_packet(incoming_packet_shared_secret, *failure_code, &data[..]).encode(); - onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &packet) - } - }, - HTLCFailReason::LightningError { err } => { - onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &err.data) - } - } - } - - fn decode_onion_failure(&self, secp_ctx: &Secp256k1, logger: &L, htlc_source: &HTLCSource) -> (Option, Option, bool, Option, Option>) where L::Target: Logger { - match self { - HTLCFailReason::LightningError { ref err } => { - onion_utils::process_onion_failure(secp_ctx, logger, &htlc_source, err.data.clone()) - }, - HTLCFailReason::Reason { ref failure_code, ref data, .. } => { - // we get a fail_malformed_htlc from the first hop - // TODO: We'd like to generate a NetworkUpdate for temporary - // failures here, but that would be insufficient as find_route - // generally ignores its view of our own channels as we provide them via - // ChannelDetails. - // TODO: For non-temporary failures, we really should be closing the - // channel here as we apparently can't relay through them anyway. - if let &HTLCSource::OutboundRoute { ref path, .. } = htlc_source { - (None, Some(path.first().unwrap().short_channel_id), true, Some(*failure_code), Some(data.clone())) - } else { unreachable!(); } - } - } - } -} - struct ReceiveError { err_code: u16, err_data: Vec, @@ -7031,16 +6956,6 @@ impl Writeable for HTLCSource { } } -impl_writeable_tlv_based_enum!(HTLCFailReason, - (0, LightningError) => { - (0, err, required), - }, - (1, Reason) => { - (0, failure_code, required), - (2, data, vec_type), - }, -;); - impl_writeable_tlv_based!(PendingAddHTLCInfo, { (0, forward_info, required), (1, prev_user_channel_id, (default_value, 0)), diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 23dc556cfac..68d5a244fb3 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -592,6 +592,92 @@ pub(super) fn process_onion_failure(secp_ctx: & } else { unreachable!(); } } +#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug +pub(super) enum HTLCFailReason { + LightningError { + err: msgs::OnionErrorPacket, + }, + Reason { + failure_code: u16, + data: Vec, + } +} + +impl core::fmt::Debug for HTLCFailReason { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { + match self { + HTLCFailReason::Reason { ref failure_code, .. } => { + write!(f, "HTLC error code {}", failure_code) + }, + HTLCFailReason::LightningError { .. } => { + write!(f, "pre-built LightningError") + } + } + } +} + +impl_writeable_tlv_based_enum!(HTLCFailReason, + (0, LightningError) => { + (0, err, required), + }, + (1, Reason) => { + (0, failure_code, required), + (2, data, vec_type), + }, +;); + +impl HTLCFailReason { + pub(super) fn reason(failure_code: u16, data: Vec) -> Self { + Self::Reason { failure_code, data } + } + + pub(super) fn from_failure_code(failure_code: u16) -> Self { + Self::Reason { failure_code, data: Vec::new() } + } + + pub(super) fn from_msg(msg: &msgs::UpdateFailHTLC) -> Self { + Self::LightningError { err: msg.reason.clone() } + } + + pub(super) fn get_encrypted_failure_packet(&self, incoming_packet_shared_secret: &[u8; 32], phantom_shared_secret: &Option<[u8; 32]>) -> msgs::OnionErrorPacket { + match self { + HTLCFailReason::Reason { ref failure_code, ref data } => { + if let Some(phantom_ss) = phantom_shared_secret { + let phantom_packet = build_failure_packet(phantom_ss, *failure_code, &data[..]).encode(); + let encrypted_phantom_packet = encrypt_failure_packet(phantom_ss, &phantom_packet); + encrypt_failure_packet(incoming_packet_shared_secret, &encrypted_phantom_packet.data[..]) + } else { + let packet = build_failure_packet(incoming_packet_shared_secret, *failure_code, &data[..]).encode(); + encrypt_failure_packet(incoming_packet_shared_secret, &packet) + } + }, + HTLCFailReason::LightningError { err } => { + encrypt_failure_packet(incoming_packet_shared_secret, &err.data) + } + } + } + + pub(super) fn decode_onion_failure(&self, secp_ctx: &Secp256k1, logger: &L, htlc_source: &HTLCSource) -> (Option, Option, bool, Option, Option>) where L::Target: Logger { + match self { + HTLCFailReason::LightningError { ref err } => { + process_onion_failure(secp_ctx, logger, &htlc_source, err.data.clone()) + }, + HTLCFailReason::Reason { ref failure_code, ref data, .. } => { + // we get a fail_malformed_htlc from the first hop + // TODO: We'd like to generate a NetworkUpdate for temporary + // failures here, but that would be insufficient as find_route + // generally ignores its view of our own channels as we provide them via + // ChannelDetails. + // TODO: For non-temporary failures, we really should be closing the + // channel here as we apparently can't relay through them anyway. + if let &HTLCSource::OutboundRoute { ref path, .. } = htlc_source { + (None, Some(path.first().unwrap().short_channel_id), true, Some(*failure_code), Some(data.clone())) + } else { unreachable!(); } + } + } + } +} + /// Allows `decode_next_hop` to return the next hop packet bytes for either payments or onion /// message forwards. pub(crate) trait NextPacketBytes: AsMut<[u8]> {