From 9177f99a4f258452fa9cda52bca0cf08aabdcbdf Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Tue, 19 Aug 2025 16:12:49 -0400 Subject: [PATCH 1/7] Rustfmt Channel::get_last_revoke_and_ack --- lightning/src/ln/channel.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 3d25934d18d..7ec00fcd004 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -8958,12 +8958,24 @@ where } } - #[rustfmt::skip] - fn get_last_revoke_and_ack(&mut self, logger: &L) -> Option where L::Target: Logger { - debug_assert!(self.holder_commitment_point.next_transaction_number() <= INITIAL_COMMITMENT_NUMBER - 2); - self.holder_commitment_point.try_resolve_pending(&self.context.holder_signer, &self.context.secp_ctx, logger); - let per_commitment_secret = self.context.holder_signer.as_ref() - .release_commitment_secret(self.holder_commitment_point.next_transaction_number() + 2).ok(); + fn get_last_revoke_and_ack(&mut self, logger: &L) -> Option + where + L::Target: Logger, + { + debug_assert!( + self.holder_commitment_point.next_transaction_number() <= INITIAL_COMMITMENT_NUMBER - 2 + ); + self.holder_commitment_point.try_resolve_pending( + &self.context.holder_signer, + &self.context.secp_ctx, + logger, + ); + let per_commitment_secret = self + .context + .holder_signer + .as_ref() + .release_commitment_secret(self.holder_commitment_point.next_transaction_number() + 2) + .ok(); if let Some(per_commitment_secret) = per_commitment_secret { if self.holder_commitment_point.can_advance() { self.context.signer_pending_revoke_and_ack = false; @@ -8973,7 +8985,7 @@ where next_per_commitment_point: self.holder_commitment_point.next_point(), #[cfg(taproot)] next_local_nonce: None, - }) + }); } } if !self.holder_commitment_point.can_advance() { From ee6d868c4a0a9f7cb24e83a63d56f124c80e6e03 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Tue, 19 Aug 2025 16:15:40 -0400 Subject: [PATCH 2/7] Clean up rustfmt'd Channel::get_last_revoke_and_ack This method was rustfmt'd in the previous commit, here we clean up that formatting. --- lightning/src/ln/channel.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 7ec00fcd004..587ee9408b6 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -8965,14 +8965,9 @@ where debug_assert!( self.holder_commitment_point.next_transaction_number() <= INITIAL_COMMITMENT_NUMBER - 2 ); - self.holder_commitment_point.try_resolve_pending( - &self.context.holder_signer, - &self.context.secp_ctx, - logger, - ); - let per_commitment_secret = self - .context - .holder_signer + let signer = &self.context.holder_signer; + self.holder_commitment_point.try_resolve_pending(signer, &self.context.secp_ctx, logger); + let per_commitment_secret = signer .as_ref() .release_commitment_secret(self.holder_commitment_point.next_transaction_number() + 2) .ok(); From 3c98cbc61b851faaa011e720b56d8231a4867107 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 20 Aug 2025 11:44:25 -0400 Subject: [PATCH 3/7] Rustfmt OutboundPayments::send_payment_for_static_invoice This method will be edited in upcoming commits, and the codebase policy is to at least consider removing rustfmt::skips when touching a method. --- lightning/src/ln/outbound_payment.rs | 76 ++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 476964db889..b1743534ad1 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -1195,12 +1195,17 @@ impl OutboundPayments { }; } - #[rustfmt::skip] pub(super) fn send_payment_for_static_invoice< - R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref + R: Deref, + ES: Deref, + NS: Deref, + NL: Deref, + IH, + SP, + L: Deref, >( - &self, payment_id: PaymentId, router: &R, first_hops: Vec, inflight_htlcs: IH, - entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL, + &self, payment_id: PaymentId, router: &R, first_hops: Vec, + inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1, best_block_height: u32, logger: &L, pending_events: &Mutex)>>, send_payment_along_path: SP, @@ -1214,24 +1219,55 @@ impl OutboundPayments { IH: Fn() -> InFlightHtlcs, SP: Fn(SendAlongPathArgs) -> Result<(), APIError>, { - let (payment_hash, keysend_preimage, route_params, retry_strategy, invoice_request, invoice) = - match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { - hash_map::Entry::Occupied(entry) => match entry.get() { - PendingOutboundPayment::StaticInvoiceReceived { - payment_hash, route_params, retry_strategy, keysend_preimage, invoice_request, static_invoice, .. - } => { - (*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy, - invoice_request.clone(), static_invoice.clone()) - }, - _ => return Err(Bolt12PaymentError::DuplicateInvoice), - }, - hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice), - }; + let ( + payment_hash, + keysend_preimage, + route_params, + retry_strategy, + invoice_request, + invoice, + ) = match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { + hash_map::Entry::Occupied(entry) => match entry.get() { + PendingOutboundPayment::StaticInvoiceReceived { + payment_hash, + route_params, + retry_strategy, + keysend_preimage, + invoice_request, + static_invoice, + .. + } => ( + *payment_hash, + *keysend_preimage, + route_params.clone(), + *retry_strategy, + invoice_request.clone(), + static_invoice.clone(), + ), + _ => return Err(Bolt12PaymentError::DuplicateInvoice), + }, + hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice), + }; let invoice = PaidBolt12Invoice::StaticInvoice(invoice); self.send_payment_for_bolt12_invoice_internal( - payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), invoice, route_params, - retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer, - node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path + payment_id, + payment_hash, + Some(keysend_preimage), + Some(&invoice_request), + invoice, + route_params, + retry_strategy, + router, + first_hops, + inflight_htlcs, + entropy_source, + node_signer, + node_id_lookup, + secp_ctx, + best_block_height, + logger, + pending_events, + send_payment_along_path, ) } From e3db976f7151528ed20b3a9f2261a4966fc6997b Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 20 Aug 2025 13:23:04 -0400 Subject: [PATCH 4/7] Rustfmt OutboundPayments::static_invoice_received This method will be edited in upcoming commits, and the codebase policy is to at least consider removing rustfmt::skips when touching a method. --- lightning/src/ln/outbound_payment.rs | 64 ++++++++++++++++++---------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index b1743534ad1..a66c21ac4ef 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -1106,12 +1106,14 @@ impl OutboundPayments { Ok(()) } - #[rustfmt::skip] pub(super) fn static_invoice_received( &self, invoice: &StaticInvoice, payment_id: PaymentId, features: Bolt12InvoiceFeatures, best_block_height: u32, duration_since_epoch: Duration, entropy_source: ES, - pending_events: &Mutex)>> - ) -> Result<(), Bolt12PaymentError> where ES::Target: EntropySource { + pending_events: &Mutex)>>, + ) -> Result<(), Bolt12PaymentError> + where + ES::Target: EntropySource, + { macro_rules! abandon_with_entry { ($payment: expr, $reason: expr) => { assert!( @@ -1130,64 +1132,82 @@ impl OutboundPayments { match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { hash_map::Entry::Occupied(mut entry) => match entry.get_mut() { PendingOutboundPayment::AwaitingInvoice { - retry_strategy, retryable_invoice_request, route_params_config, .. + retry_strategy, + retryable_invoice_request, + route_params_config, + .. } => { let invreq = &retryable_invoice_request .as_ref() .ok_or(Bolt12PaymentError::UnexpectedInvoice)? .invoice_request; if !invoice.is_from_same_offer(invreq) { - return Err(Bolt12PaymentError::UnexpectedInvoice) + return Err(Bolt12PaymentError::UnexpectedInvoice); } if invoice.invoice_features().requires_unknown_bits_from(&features) { abandon_with_entry!(entry, PaymentFailureReason::UnknownRequiredFeatures); - return Err(Bolt12PaymentError::UnknownRequiredFeatures) + return Err(Bolt12PaymentError::UnknownRequiredFeatures); } - if duration_since_epoch > invoice.created_at().saturating_add(invoice.relative_expiry()) { + if duration_since_epoch + > invoice.created_at().saturating_add(invoice.relative_expiry()) + { abandon_with_entry!(entry, PaymentFailureReason::PaymentExpired); - return Err(Bolt12PaymentError::SendingFailed(RetryableSendFailure::PaymentExpired)) + return Err(Bolt12PaymentError::SendingFailed( + RetryableSendFailure::PaymentExpired, + )); } - let amount_msat = match InvoiceBuilder::::amount_msats(invreq) { + let amount_msat = match InvoiceBuilder::::amount_msats( + invreq, + ) { Ok(amt) => amt, Err(_) => { // We check this during invoice request parsing, when constructing the invreq's // contents from its TLV stream. debug_assert!(false, "LDK requires an msat amount in either the invreq or the invreq's underlying offer"); abandon_with_entry!(entry, PaymentFailureReason::UnexpectedError); - return Err(Bolt12PaymentError::UnknownRequiredFeatures) - } + return Err(Bolt12PaymentError::UnknownRequiredFeatures); + }, }; - let keysend_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes()); - let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array()); + let keysend_preimage = + PaymentPreimage(entropy_source.get_secure_random_bytes()); + let payment_hash = + PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array()); let pay_params = PaymentParameters::from_static_invoice(invoice) .with_user_config_ignoring_fee_limit(*route_params_config); - let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat); - route_params.max_total_routing_fee_msat = route_params_config.max_total_routing_fee_msat; + let mut route_params = + RouteParameters::from_payment_params_and_value(pay_params, amount_msat); + route_params.max_total_routing_fee_msat = + route_params_config.max_total_routing_fee_msat; if let Err(()) = onion_utils::set_max_path_length( - &mut route_params, &RecipientOnionFields::spontaneous_empty(), Some(keysend_preimage), - Some(invreq), best_block_height + &mut route_params, + &RecipientOnionFields::spontaneous_empty(), + Some(keysend_preimage), + Some(invreq), + best_block_height, ) { abandon_with_entry!(entry, PaymentFailureReason::RouteNotFound); - return Err(Bolt12PaymentError::SendingFailed(RetryableSendFailure::OnionPacketSizeExceeded)) + return Err(Bolt12PaymentError::SendingFailed( + RetryableSendFailure::OnionPacketSizeExceeded, + )); } - let absolute_expiry = duration_since_epoch.saturating_add(ASYNC_PAYMENT_TIMEOUT_RELATIVE_EXPIRY); + let absolute_expiry = + duration_since_epoch.saturating_add(ASYNC_PAYMENT_TIMEOUT_RELATIVE_EXPIRY); *entry.into_mut() = PendingOutboundPayment::StaticInvoiceReceived { payment_hash, keysend_preimage, retry_strategy: *retry_strategy, route_params, - invoice_request: - retryable_invoice_request + invoice_request: retryable_invoice_request .take() .ok_or(Bolt12PaymentError::UnexpectedInvoice)? .invoice_request, static_invoice: invoice.clone(), expiry_time: absolute_expiry, }; - return Ok(()) + return Ok(()); }, _ => return Err(Bolt12PaymentError::DuplicateInvoice), }, From 84c997df0cbf26f7db04b885b51f595120d7ef08 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Fri, 15 Aug 2025 23:45:28 -0400 Subject: [PATCH 5/7] DRY HTLCPreviousHopData creation In upcoming commits, we will be adding several more conversions from PendingAddHTLCInfo into HTLCPreviousHopData. This conversion gets repeated all over the ChannelManager already, so lay some groundwork by DRYing it up. --- lightning/src/ln/channelmanager.rs | 227 ++++++++++++----------------- 1 file changed, 93 insertions(+), 134 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index cfef0540a97..d28b48084b3 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -449,6 +449,27 @@ pub(super) struct PendingAddHTLCInfo { prev_user_channel_id: u128, } +impl PendingAddHTLCInfo { + fn htlc_previous_hop_data(&self) -> HTLCPreviousHopData { + let phantom_shared_secret = match self.forward_info.routing { + PendingHTLCRouting::Receive { phantom_shared_secret, .. } => phantom_shared_secret, + _ => None, + }; + HTLCPreviousHopData { + short_channel_id: self.prev_short_channel_id, + user_channel_id: Some(self.prev_user_channel_id), + outpoint: self.prev_funding_outpoint, + channel_id: self.prev_channel_id, + counterparty_node_id: Some(self.prev_counterparty_node_id), + htlc_id: self.prev_htlc_id, + incoming_packet_shared_secret: self.forward_info.incoming_shared_secret, + phantom_shared_secret, + blinded_failure: self.forward_info.routing.blinded_failure(), + cltv_expiry: self.forward_info.routing.incoming_cltv_expiry(), + } + } +} + #[cfg_attr(test, derive(Clone, Debug, PartialEq))] pub(super) enum HTLCForwardInfo { AddHTLC(PendingAddHTLCInfo), @@ -6294,20 +6315,8 @@ where err: format!("Payment with intercept id {} not found", log_bytes!(intercept_id.0)) })?; - if let PendingHTLCRouting::Forward { short_channel_id, incoming_cltv_expiry, .. } = payment.forward_info.routing { - let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: payment.prev_short_channel_id, - user_channel_id: Some(payment.prev_user_channel_id), - outpoint: payment.prev_funding_outpoint, - channel_id: payment.prev_channel_id, - counterparty_node_id: Some(payment.prev_counterparty_node_id), - htlc_id: payment.prev_htlc_id, - incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret, - phantom_shared_secret: None, - blinded_failure: payment.forward_info.routing.blinded_failure(), - cltv_expiry: incoming_cltv_expiry, - }); - + if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing { + let htlc_source = HTLCSource::PreviousHopData(payment.htlc_previous_hop_data()); let reason = HTLCFailReason::from_failure_code(LocalHTLCFailureReason::UnknownNextPeer); let destination = HTLCHandlingFailureType::InvalidForward { requested_forward_scid: short_channel_id }; self.fail_htlc_backwards_internal(&htlc_source, &payment.forward_info.payment_hash, &reason, destination); @@ -6629,24 +6638,24 @@ where ) { for forward_info in forward_infos { match forward_info { - HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, - prev_htlc_id, - prev_channel_id, - prev_funding_outpoint, - prev_user_channel_id, - prev_counterparty_node_id, - forward_info: - PendingHTLCInfo { - routing, - incoming_shared_secret, - payment_hash, - outgoing_amt_msat, - outgoing_cltv_value, - .. - }, - }) => { - let cltv_expiry = routing.incoming_cltv_expiry(); + HTLCForwardInfo::AddHTLC(payment) => { + let PendingAddHTLCInfo { + prev_short_channel_id, + prev_htlc_id, + prev_channel_id, + prev_funding_outpoint, + prev_user_channel_id, + prev_counterparty_node_id, + forward_info: + PendingHTLCInfo { + ref routing, + incoming_shared_secret, + payment_hash, + outgoing_amt_msat, + outgoing_cltv_value, + .. + }, + } = payment; let logger = WithContext::from( &self.logger, forwarding_counterparty, @@ -6657,19 +6666,11 @@ where |msg, reason, err_data, phantom_ss, next_hop_unknown| { log_info!(logger, "Failed to accept/forward incoming HTLC: {}", msg); - let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: prev_short_channel_id, - user_channel_id: Some(prev_user_channel_id), - channel_id: prev_channel_id, - outpoint: prev_funding_outpoint, - counterparty_node_id: Some(prev_counterparty_node_id), - htlc_id: prev_htlc_id, - incoming_packet_shared_secret: incoming_shared_secret, - phantom_shared_secret: phantom_ss, - blinded_failure: routing.blinded_failure(), - cltv_expiry, - }); - + let mut prev_hop = payment.htlc_previous_hop_data(); + // Override the phantom shared secret because it wasn't set in the originating + // `PendingAddHTLCInfo` above, it was calculated below after detecting this as a + // phantom payment. + prev_hop.phantom_shared_secret = phantom_ss; let failure_type = if next_hop_unknown { HTLCHandlingFailureType::InvalidForward { requested_forward_scid: short_chan_id, @@ -6679,7 +6680,7 @@ where }; failed_forwards.push(( - htlc_source, + HTLCSource::PreviousHopData(prev_hop), payment_hash, HTLCFailReason::reason(reason, err_data), failure_type, @@ -6848,43 +6849,29 @@ where let mut draining_pending_forwards = pending_forwards.drain(..); while let Some(forward_info) = draining_pending_forwards.next() { let queue_fail_htlc_res = match forward_info { - HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, - prev_htlc_id, - prev_channel_id, - prev_funding_outpoint, - prev_user_channel_id, - prev_counterparty_node_id, - forward_info: - PendingHTLCInfo { - incoming_shared_secret, - payment_hash, - outgoing_amt_msat, - outgoing_cltv_value, - routing: - PendingHTLCRouting::Forward { - ref onion_packet, - blinded, - incoming_cltv_expiry, - .. - }, - skimmed_fee_msat, - .. + HTLCForwardInfo::AddHTLC(ref payment) => { + let htlc_source = HTLCSource::PreviousHopData(payment.htlc_previous_hop_data()); + let PendingAddHTLCInfo { + prev_short_channel_id, + forward_info: + PendingHTLCInfo { + payment_hash, + outgoing_amt_msat, + outgoing_cltv_value, + routing, + skimmed_fee_msat, + .. + }, + .. + } = payment; + let (onion_packet, blinded) = match routing { + PendingHTLCRouting::Forward { ref onion_packet, blinded, .. } => { + (onion_packet, blinded) }, - }) => { - let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: prev_short_channel_id, - user_channel_id: Some(prev_user_channel_id), - counterparty_node_id: Some(prev_counterparty_node_id), - channel_id: prev_channel_id, - outpoint: prev_funding_outpoint, - htlc_id: prev_htlc_id, - incoming_packet_shared_secret: incoming_shared_secret, - // Phantom payments are only PendingHTLCRouting::Receive. - phantom_shared_secret: None, - blinded_failure: blinded.map(|b| b.failure), - cltv_expiry: incoming_cltv_expiry, - }); + _ => { + panic!("short_channel_id != 0 should imply any pending_forward entries are of type Forward"); + }, + }; let next_blinding_point = blinded.and_then(|b| { b.next_blinding_override.or_else(|| { let encrypted_tlvs_ss = self @@ -6950,7 +6937,7 @@ where let logger = WithChannelContext::from( &self.logger, &optimal_channel.context, - Some(payment_hash), + Some(*payment_hash), ); let channel_description = if optimal_channel.funding.get_short_channel_id() == Some(short_chan_id) { @@ -6961,12 +6948,12 @@ where log_trace!(logger, "Forwarding HTLC from SCID {} with payment_hash {} and next hop SCID {} over {} channel {} with corresponding peer {}", prev_short_channel_id, &payment_hash, short_chan_id, channel_description, optimal_channel.context.channel_id(), &counterparty_node_id); if let Err((reason, msg)) = optimal_channel.queue_add_htlc( - outgoing_amt_msat, - payment_hash, - outgoing_cltv_value, + *outgoing_amt_msat, + *payment_hash, + *outgoing_cltv_value, htlc_source.clone(), onion_packet.clone(), - skimmed_fee_msat, + *skimmed_fee_msat, next_blinding_point, &self.fee_estimator, &&logger, @@ -6991,7 +6978,7 @@ where }; failed_forwards.push(( htlc_source, - payment_hash, + *payment_hash, HTLCFailReason::reason(reason, data), failure_type, )); @@ -7008,9 +6995,6 @@ where } None }, - HTLCForwardInfo::AddHTLC { .. } => { - panic!("short_channel_id != 0 should imply any pending_forward entries are of type Forward"); - }, HTLCForwardInfo::FailHTLC { htlc_id, ref err_packet } => { if let Some(chan) = peer_state .channel_by_id @@ -7094,24 +7078,22 @@ where ) { 'next_forwardable_htlc: for forward_info in pending_forwards.drain(..) { match forward_info { - HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, - prev_htlc_id, - prev_channel_id, - prev_funding_outpoint, - prev_user_channel_id, - prev_counterparty_node_id, - forward_info: - PendingHTLCInfo { - routing, - incoming_shared_secret, - payment_hash, - incoming_amt_msat, - outgoing_amt_msat, - skimmed_fee_msat, - .. - }, - }) => { + HTLCForwardInfo::AddHTLC(payment) => { + let prev_hop = payment.htlc_previous_hop_data(); + let PendingAddHTLCInfo { + prev_channel_id, + prev_funding_outpoint, + forward_info: + PendingHTLCInfo { + routing, + payment_hash, + incoming_amt_msat, + outgoing_amt_msat, + skimmed_fee_msat, + .. + }, + .. + } = payment; let blinded_failure = routing.blinded_failure(); let ( cltv_expiry, @@ -7183,18 +7165,7 @@ where }, }; let claimable_htlc = ClaimableHTLC { - prev_hop: HTLCPreviousHopData { - short_channel_id: prev_short_channel_id, - user_channel_id: Some(prev_user_channel_id), - counterparty_node_id: Some(prev_counterparty_node_id), - channel_id: prev_channel_id, - outpoint: prev_funding_outpoint, - htlc_id: prev_htlc_id, - incoming_packet_shared_secret: incoming_shared_secret, - phantom_shared_secret, - blinded_failure, - cltv_expiry: Some(cltv_expiry), - }, + prev_hop, // We differentiate the received value from the sender intended value // if possible so that we don't prematurely mark MPP payments complete // if routing nodes overpay @@ -13701,19 +13672,7 @@ where let mut intercepted_htlcs = self.pending_intercepted_htlcs.lock().unwrap(); intercepted_htlcs.retain(|_, htlc| { if height >= htlc.forward_info.outgoing_cltv_value - HTLC_FAIL_BACK_BUFFER { - let prev_hop_data = HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: htlc.prev_short_channel_id, - user_channel_id: Some(htlc.prev_user_channel_id), - htlc_id: htlc.prev_htlc_id, - incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret, - phantom_shared_secret: None, - counterparty_node_id: Some(htlc.prev_counterparty_node_id), - outpoint: htlc.prev_funding_outpoint, - channel_id: htlc.prev_channel_id, - blinded_failure: htlc.forward_info.routing.blinded_failure(), - cltv_expiry: htlc.forward_info.routing.incoming_cltv_expiry(), - }); - + let prev_hop_data = HTLCSource::PreviousHopData(htlc.htlc_previous_hop_data()); let requested_forward_scid /* intercept scid */ = match htlc.forward_info.routing { PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id, _ => unreachable!(), From 8173ac0c87c7dc0b303c277b0829bf16d3385aaf Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Sat, 16 Aug 2025 00:32:30 -0400 Subject: [PATCH 6/7] DRY PendingAddHTLCInfo creation in forward_htlcs Without this DRYing, we would be repeating the same code to instantiate the PendingAddHTLCInfo several more times in this method, in upcoming commits. --- lightning/src/ln/channelmanager.rs | 76 ++++++++++-------------------- 1 file changed, 24 insertions(+), 52 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d28b48084b3..19852395a62 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10628,28 +10628,30 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ let is_our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid); let mut forward_htlcs = self.forward_htlcs.lock().unwrap(); + let payment_hash = forward_info.payment_hash; + let pending_add = PendingAddHTLCInfo { + prev_short_channel_id, + prev_counterparty_node_id, + prev_funding_outpoint, + prev_channel_id, + prev_htlc_id, + prev_user_channel_id, + forward_info, + }; match forward_htlcs.entry(scid) { hash_map::Entry::Occupied(mut entry) => { - entry.get_mut().push(HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, - prev_counterparty_node_id, - prev_funding_outpoint, - prev_channel_id, - prev_htlc_id, - prev_user_channel_id, - forward_info, - })); + entry.get_mut().push(HTLCForwardInfo::AddHTLC(pending_add)); }, hash_map::Entry::Vacant(entry) => { if !is_our_scid - && forward_info.incoming_amt_msat.is_some() + && pending_add.forward_info.incoming_amt_msat.is_some() && fake_scid::is_valid_intercept( &self.fake_scid_rand_bytes, scid, &self.chain_hash, ) { let intercept_id = InterceptId( - Sha256::hash(&forward_info.incoming_shared_secret) + Sha256::hash(&pending_add.forward_info.incoming_shared_secret) .to_byte_array(), ); let mut pending_intercepts = @@ -10659,57 +10661,35 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ new_intercept_events.push_back(( events::Event::HTLCIntercepted { requested_next_hop_scid: scid, - payment_hash: forward_info.payment_hash, - inbound_amount_msat: forward_info + payment_hash, + inbound_amount_msat: pending_add + .forward_info .incoming_amt_msat .unwrap(), - expected_outbound_amount_msat: forward_info + expected_outbound_amount_msat: pending_add + .forward_info .outgoing_amt_msat, intercept_id, }, None, )); - entry.insert(PendingAddHTLCInfo { - prev_short_channel_id, - prev_counterparty_node_id, - prev_funding_outpoint, - prev_channel_id, - prev_htlc_id, - prev_user_channel_id, - forward_info, - }); + entry.insert(pending_add); }, hash_map::Entry::Occupied(_) => { let logger = WithContext::from( &self.logger, None, Some(prev_channel_id), - Some(forward_info.payment_hash), + Some(payment_hash), ); log_info!( logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid ); - let routing = &forward_info.routing; - let htlc_source = - HTLCSource::PreviousHopData(HTLCPreviousHopData { - short_channel_id: prev_short_channel_id, - user_channel_id: Some(prev_user_channel_id), - counterparty_node_id: Some( - prev_counterparty_node_id, - ), - outpoint: prev_funding_outpoint, - channel_id: prev_channel_id, - htlc_id: prev_htlc_id, - incoming_packet_shared_secret: forward_info - .incoming_shared_secret, - phantom_shared_secret: None, - blinded_failure: routing.blinded_failure(), - cltv_expiry: routing.incoming_cltv_expiry(), - }); - - let payment_hash = forward_info.payment_hash; + let htlc_source = HTLCSource::PreviousHopData( + pending_add.htlc_previous_hop_data(), + ); let reason = HTLCFailReason::from_failure_code( LocalHTLCFailureReason::UnknownNextPeer, ); @@ -10726,15 +10706,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ }, } } else { - entry.insert(vec![HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo { - prev_short_channel_id, - prev_counterparty_node_id, - prev_funding_outpoint, - prev_channel_id, - prev_htlc_id, - prev_user_channel_id, - forward_info, - })]); + entry.insert(vec![HTLCForwardInfo::AddHTLC(pending_add)]); } }, } From 11f3476c2b0c164ef85f5adfc2cfa9c5356d14a8 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Tue, 2 Sep 2025 16:56:26 -0400 Subject: [PATCH 7/7] Make BlindedMessagePath creation infallible The LDK codebase in general is comfortable panicking if the entropy source provided to it is dysfunctional. Up until now we made an exception for blinded path creation, where we would handle an error that could occur on mul_tweak that could only occur if the session_priv provided was not actually random. In comparable cases in onion_utils, we would panic instead. In upcoming commits, we will be including blinded paths in outbound revoke_and_ack messages as part of implementing async payments, where it is difficult to handle failing back an HTLC if blinded path creation fails. Thus we now have an incentive to make the blinded path creation methods infallible, so do so here. --- lightning-dns-resolver/src/lib.rs | 6 +-- lightning/src/blinded_path/message.rs | 21 +++----- lightning/src/blinded_path/payment.rs | 6 +-- lightning/src/blinded_path/utils.rs | 32 +++++------ lightning/src/ln/blinded_payment_tests.rs | 10 ++-- .../src/onion_message/functional_tests.rs | 54 +++++++------------ lightning/src/onion_message/messenger.rs | 23 ++++---- 7 files changed, 58 insertions(+), 94 deletions(-) diff --git a/lightning-dns-resolver/src/lib.rs b/lightning-dns-resolver/src/lib.rs index fc591c8c153..3d8e1b3cd9b 100644 --- a/lightning-dns-resolver/src/lib.rs +++ b/lightning-dns-resolver/src/lib.rs @@ -239,8 +239,7 @@ mod test { context, &keys, secp_ctx, - ) - .unwrap()]) + )]) } } impl Deref for DirectlyConnectedRouter { @@ -349,8 +348,7 @@ mod test { query_context, &*payer_keys, &secp_ctx, - ) - .unwrap(); + ); payer.pending_messages.lock().unwrap().push(( DNSResolverMessage::DNSSECQuery(msg), MessageSendInstructions::WithSpecifiedReplyPath { diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 8105bb206ee..7d721cd1fdc 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -57,23 +57,19 @@ impl BlindedMessagePath { pub fn one_hop( recipient_node_id: PublicKey, local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1, - ) -> Result + ) -> Self where ES::Target: EntropySource, { Self::new(&[], recipient_node_id, local_node_receive_key, context, entropy_source, secp_ctx) } - /// Create a path for an onion message, to be forwarded along `node_pks`. The last node - /// pubkey in `node_pks` will be the destination node. - /// - /// Errors if no hops are provided or if `node_pk`(s) are invalid. - // TODO: make all payloads the same size with padding + add dummy hops + /// Create a path for an onion message, to be forwarded along `node_pks`. pub fn new( intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey, local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1, - ) -> Result + ) -> Self where ES::Target: EntropySource, { @@ -96,7 +92,7 @@ impl BlindedMessagePath { intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey, dummy_hop_count: usize, local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1, - ) -> Result + ) -> Self where ES::Target: EntropySource, { @@ -107,7 +103,7 @@ impl BlindedMessagePath { let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); - Ok(Self(BlindedPath { + Self(BlindedPath { introduction_node, blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), blinded_hops: blinded_hops( @@ -118,9 +114,8 @@ impl BlindedMessagePath { context, &blinding_secret, local_node_receive_key, - ) - .map_err(|_| ())?, - })) + ), + }) } /// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed @@ -669,7 +664,7 @@ pub(super) fn blinded_hops( secp_ctx: &Secp256k1, intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey, dummy_hop_count: usize, context: MessageContext, session_priv: &SecretKey, local_node_receive_key: ReceiveAuthKey, -) -> Result, secp256k1::Error> { +) -> Vec { let dummy_count = cmp::min(dummy_hop_count, MAX_DUMMY_HOPS_COUNT); let pks = intermediate_nodes .iter() diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 96913ef3c62..4ae10f75961 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -116,7 +116,6 @@ impl BlindedPaymentPath { /// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`. /// /// Errors if: - /// * a provided node id is invalid /// * [`BlindedPayInfo`] calculation results in an integer overflow /// * any unknown features are required in the provided [`ForwardTlvs`] // TODO: make all payloads the same size with padding + add dummy hops @@ -151,8 +150,7 @@ impl BlindedPaymentPath { payee_node_id, payee_tlvs, &blinding_secret, - ) - .map_err(|_| ())?, + ), }, payinfo: blinded_payinfo, }) @@ -663,7 +661,7 @@ pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30; pub(super) fn blinded_hops( secp_ctx: &Secp256k1, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, session_priv: &SecretKey, -) -> Result, secp256k1::Error> { +) -> Vec { let pks = intermediate_nodes .iter() .map(|node| (node.node_id, None)) diff --git a/lightning/src/blinded_path/utils.rs b/lightning/src/blinded_path/utils.rs index 3956fd9bcdf..5fc359a47d9 100644 --- a/lightning/src/blinded_path/utils.rs +++ b/lightning/src/blinded_path/utils.rs @@ -51,10 +51,8 @@ macro_rules! build_keys_helper { hmac.input(encrypted_data_ss.as_ref()); Hmac::from_engine(hmac).to_byte_array() }; - pk.mul_tweak( - $secp_ctx, - &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap(), - )? + pk.mul_tweak($secp_ctx, &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap()) + .expect("RNG is busted") }; let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv); @@ -84,9 +82,9 @@ macro_rules! build_keys_helper { Sha256::from_engine(sha).to_byte_array() }; - msg_blinding_point_priv = msg_blinding_point_priv.mul_tweak( - &Scalar::from_be_bytes(msg_blinding_point_blinding_factor).unwrap(), - )?; + msg_blinding_point_priv = msg_blinding_point_priv + .mul_tweak(&Scalar::from_be_bytes(msg_blinding_point_blinding_factor).unwrap()) + .expect("RNG is busted"); msg_blinding_point = PublicKey::from_secret_key($secp_ctx, &msg_blinding_point_priv); @@ -96,9 +94,9 @@ macro_rules! build_keys_helper { sha.input(onion_packet_ss.as_ref()); Sha256::from_engine(sha).to_byte_array() }; - onion_packet_pubkey_priv = onion_packet_pubkey_priv.mul_tweak( - &Scalar::from_be_bytes(onion_packet_pubkey_blinding_factor).unwrap(), - )?; + onion_packet_pubkey_priv = onion_packet_pubkey_priv + .mul_tweak(&Scalar::from_be_bytes(onion_packet_pubkey_blinding_factor).unwrap()) + .expect("RNG is busted"); onion_packet_pubkey = PublicKey::from_secret_key($secp_ctx, &onion_packet_pubkey_priv); }; @@ -109,8 +107,7 @@ macro_rules! build_keys_helper { pub(crate) fn construct_keys_for_onion_message<'a, T, I, F>( secp_ctx: &Secp256k1, unblinded_path: I, destination: Destination, session_priv: &SecretKey, mut callback: F, -) -> Result<(), secp256k1::Error> -where +) where T: secp256k1::Signing + secp256k1::Verification, I: Iterator, F: FnMut(SharedSecret, PublicKey, [u8; 32], Option, Option>), @@ -134,13 +131,11 @@ where } }, } - Ok(()) } fn construct_keys_for_blinded_path<'a, T, I, F, H>( secp_ctx: &Secp256k1, unblinded_path: I, session_priv: &SecretKey, mut callback: F, -) -> Result<(), secp256k1::Error> -where +) where T: secp256k1::Signing + secp256k1::Verification, H: Borrow, I: Iterator, @@ -151,7 +146,6 @@ where for pk in unblinded_path { build_keys_in_loop!(pk, false, None); } - Ok(()) } struct PublicKeyWithTlvs { @@ -168,7 +162,7 @@ impl Borrow for PublicKeyWithTlvs { pub(crate) fn construct_blinded_hops<'a, T, I, W>( secp_ctx: &Secp256k1, unblinded_path: I, session_priv: &SecretKey, -) -> Result, secp256k1::Error> +) -> Vec where T: secp256k1::Signing + secp256k1::Verification, I: Iterator), W)>, @@ -194,8 +188,8 @@ where ), }); }, - )?; - Ok(blinded_hops) + ); + blinded_hops } /// Encrypt TLV payload to be used as a [`crate::blinded_path::BlindedHop::encrypted_payload`]. diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 8db793054dc..a8e7af23984 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -1552,7 +1552,7 @@ fn route_blinding_spec_test_vector() { ]; let mut dave_eve_blinded_hops = blinded_path::utils::construct_blinded_hops( &secp_ctx, path.into_iter(), &dave_eve_session_priv, - ).unwrap(); + ); // Concatenate an additional Bob -> Carol blinded path to the Eve -> Dave blinded path. let bob_carol_session_priv = secret_from_hex("0202020202020202020202020202020202020202020202020202020202020202"); @@ -1563,7 +1563,7 @@ fn route_blinding_spec_test_vector() { ]; let bob_carol_blinded_hops = blinded_path::utils::construct_blinded_hops( &secp_ctx, path.into_iter(), &bob_carol_session_priv, - ).unwrap(); + ); let mut blinded_hops = bob_carol_blinded_hops; blinded_hops.append(&mut dave_eve_blinded_hops); @@ -2030,7 +2030,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) { let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))]; blinded_path::utils::construct_blinded_hops( &secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv, - ).unwrap() + ) } else { let payee_tlvs = blinded_path::payment::TrampolineForwardTlvs { next_trampoline: alice_node_id, @@ -2051,7 +2051,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) { let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))]; blinded_path::utils::construct_blinded_hops( &secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv, - ).unwrap() + ) }; let route = Route { @@ -2255,7 +2255,7 @@ fn test_trampoline_unblinded_receive() { let carol_blinding_point = PublicKey::from_secret_key(&secp_ctx, &carol_alice_trampoline_session_priv); let carol_blinded_hops = blinded_path::utils::construct_blinded_hops( &secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv, - ).unwrap(); + ); let route = Route { paths: vec![Path { diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 4bec3dc31b3..1cbea9fef8d 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -437,8 +437,7 @@ fn one_blinded_hop() { let entropy = &*nodes[1].entropy_source; let receive_key = nodes[1].messenger.node_signer.get_receive_auth_key(); let blinded_path = - BlindedMessagePath::new(&[], nodes[1].node_id, receive_key, context, entropy, &secp_ctx) - .unwrap(); + BlindedMessagePath::new(&[], nodes[1].node_id, receive_key, context, entropy, &secp_ctx); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap(); @@ -463,8 +462,7 @@ fn blinded_path_with_dummy_hops() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); // Ensure that dummy hops are added to the blinded path. assert_eq!(blinded_path.blinded_hops().len(), 6); let destination = Destination::BlindedPath(blinded_path); @@ -492,8 +490,7 @@ fn two_unblinded_two_blinded() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let path = OnionMessagePath { intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id], destination: Destination::BlindedPath(blinded_path), @@ -525,8 +522,7 @@ fn three_blinded_hops() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -553,8 +549,7 @@ fn async_response_over_one_blinded_hop() { let entropy = &*nodes[1].entropy_source; let receive_key = nodes[1].messenger.node_signer.get_receive_auth_key(); let reply_path = - BlindedMessagePath::new(&[], nodes[1].node_id, receive_key, context, entropy, &secp_ctx) - .unwrap(); + BlindedMessagePath::new(&[], nodes[1].node_id, receive_key, context, entropy, &secp_ctx); // 4. Create a responder using the reply path for Alice. let responder = Some(Responder::new(reply_path)); @@ -595,8 +590,7 @@ fn async_response_with_reply_path_succeeds() { let entropy = &*bob.entropy_source; let receive_key = bob.messenger.node_signer.get_receive_auth_key(); let reply_path = - BlindedMessagePath::new(&[], bob.node_id, receive_key, context, entropy, &secp_ctx) - .unwrap(); + BlindedMessagePath::new(&[], bob.node_id, receive_key, context, entropy, &secp_ctx); // Alice asynchronously responds to Bob, expecting a response back from him. let responder = Responder::new(reply_path); @@ -638,8 +632,7 @@ fn async_response_with_reply_path_fails() { let entropy = &*bob.entropy_source; let receive_key = bob.messenger.node_signer.get_receive_auth_key(); let reply_path = - BlindedMessagePath::new(&[], bob.node_id, receive_key, context, entropy, &secp_ctx) - .unwrap(); + BlindedMessagePath::new(&[], bob.node_id, receive_key, context, entropy, &secp_ctx); // Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced and // disconnected. Thus, a reply path could no be created for the response. @@ -697,8 +690,7 @@ fn test_blinded_path_padding_for_full_length_path() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); assert!(is_padded(&blinded_path.blinded_hops(), MESSAGE_PADDING_ROUND_OFF)); @@ -734,8 +726,7 @@ fn test_blinded_path_no_padding_for_compact_path() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); assert!(!is_padded(&blinded_path.blinded_hops(), MESSAGE_PADDING_ROUND_OFF)); } @@ -762,8 +753,7 @@ fn we_are_intro_node() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -784,8 +774,7 @@ fn we_are_intro_node() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -814,8 +803,7 @@ fn invalid_blinded_path_error() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); blinded_path.clear_blinded_hops(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -850,8 +838,7 @@ fn reply_path() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); nodes[0] .messenger .send_onion_message_using_path(path, test_msg.clone(), Some(reply_path)) @@ -878,8 +865,7 @@ fn reply_path() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let intermediate_nodes = [ MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, @@ -895,8 +881,7 @@ fn reply_path() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let instructions = MessageSendInstructions::WithSpecifiedReplyPath { destination, reply_path }; nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap(); @@ -1000,8 +985,7 @@ fn requests_peer_connection_for_buffered_messages() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -1049,8 +1033,7 @@ fn drops_buffered_messages_waiting_for_peer_connection() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -1114,8 +1097,7 @@ fn intercept_offline_peer_oms() { context, entropy, &secp_ctx, - ) - .unwrap(); + ); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index ede82b41aa8..4fe2a63ae16 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -272,7 +272,7 @@ where /// ]; /// let context = MessageContext::Custom(Vec::new()); /// let receive_key = keys_manager.get_receive_auth_key(); -/// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, receive_key, context, &keys_manager, &secp_ctx).unwrap(); +/// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, receive_key, context, &keys_manager, &secp_ctx); /// /// // Send a custom onion message to a blinded path. /// let destination = Destination::BlindedPath(blinded_path); @@ -627,16 +627,14 @@ where .into_iter() .map(|(peer, _, _)| build_path(&[peer])) .take(MAX_PATHS) - .collect::, _>>() - .ok() - .filter(|paths| !paths.is_empty()) - .or_else(|| { - is_recipient_announced - .then(|| build_path(&[])) - .and_then(|result| result.ok()) - .map(|path| vec![path]) - }) - .ok_or(())?; + .collect::>(); + if paths.is_empty() { + if is_recipient_announced { + paths = vec![build_path(&[])]; + } else { + return Err(()); + } + } // Sanity check: Ones the paths are created for the non-compact case, ensure // each of them are of the length `PADDED_PATH_LENGTH`. @@ -2464,8 +2462,7 @@ fn packet_payloads_and_keys< mu, }); }, - ) - .map_err(|e| SendError::Secp256k1(e))?; + ); if let Some(control_tlvs) = final_control_tlvs { payloads.push((