From: Matt Corallo Date: Thu, 1 Dec 2022 19:08:53 +0000 (+0000) Subject: Decode `HTLCFailReason`s in a util method on the enum X-Git-Tag: v0.0.113~13^2~10 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=6c984bf50d2d22d979d5b4f7f75b5a6b428dc980;p=rust-lightning Decode `HTLCFailReason`s in a util method on the enum --- diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index fa792cc0..3b1c9d54 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -326,6 +326,26 @@ impl HTLCFailReason { } } } + + 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 { @@ -4080,90 +4100,48 @@ impl ChannelManager { + let path_failure = { #[cfg(test)] - let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone()); + let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_error.decode_onion_failure(&self.secp_ctx, &self.logger, &source); #[cfg(not(test))] - let (network_update, short_channel_id, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone()); - - if self.payment_is_probe(payment_hash, &payment_id) { - if !payment_retryable { - events::Event::ProbeSuccessful { - payment_id: *payment_id, - payment_hash: payment_hash.clone(), - path: path.clone(), - } - } else { - events::Event::ProbeFailed { - payment_id: *payment_id, - payment_hash: payment_hash.clone(), - path: path.clone(), - short_channel_id, - } - } - } else { - // TODO: If we decided to blame ourselves (or one of our channels) in - // process_onion_failure we should close that channel as it implies our - // next-hop is needlessly blaming us! - if let Some(scid) = short_channel_id { - retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid)); - } - events::Event::PaymentPathFailed { - payment_id: Some(*payment_id), - payment_hash: payment_hash.clone(), - payment_failed_permanently: !payment_retryable, - network_update, - all_paths_failed, - path: path.clone(), - short_channel_id, - retry, - #[cfg(test)] - error_code: onion_error_code, - #[cfg(test)] - error_data: onion_error_data - } - } - }, - &HTLCFailReason::Reason { -#[cfg(test)] - ref failure_code, -#[cfg(test)] - 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. - let scid = path.first().unwrap().short_channel_id; - retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid)); - - if self.payment_is_probe(payment_hash, &payment_id) { - events::Event::ProbeFailed { + let (network_update, short_channel_id, payment_retryable, _, _) = onion_error.decode_onion_failure(&self.secp_ctx, &self.logger, &source); + + if self.payment_is_probe(payment_hash, &payment_id) { + if !payment_retryable { + events::Event::ProbeSuccessful { payment_id: *payment_id, payment_hash: payment_hash.clone(), path: path.clone(), - short_channel_id: Some(scid), } } else { - events::Event::PaymentPathFailed { - payment_id: Some(*payment_id), + events::Event::ProbeFailed { + payment_id: *payment_id, payment_hash: payment_hash.clone(), - payment_failed_permanently: false, - network_update: None, - all_paths_failed, path: path.clone(), - short_channel_id: Some(scid), - retry, -#[cfg(test)] - error_code: Some(*failure_code), -#[cfg(test)] - error_data: Some(data.clone()), + short_channel_id, } } + } else { + // TODO: If we decided to blame ourselves (or one of our channels) in + // process_onion_failure we should close that channel as it implies our + // next-hop is needlessly blaming us! + if let Some(scid) = short_channel_id { + retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid)); + } + events::Event::PaymentPathFailed { + payment_id: Some(*payment_id), + payment_hash: payment_hash.clone(), + payment_failed_permanently: !payment_retryable, + network_update, + all_paths_failed, + path: path.clone(), + short_channel_id, + retry, + #[cfg(test)] + error_code: onion_error_code, + #[cfg(test)] + error_data: onion_error_data + } } }; let mut pending_events = self.pending_events.lock().unwrap();