From: Valentine Wallace Date: Mon, 15 Apr 2024 20:31:29 +0000 (-0400) Subject: outbound_payment: set max path length in PaymentParameters. X-Git-Tag: v0.0.124-beta~116^2~2 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=f0b5c582013903e4b1da61896528fb2972e84365;p=rust-lightning outbound_payment: set max path length in PaymentParameters. So the router knows how long the maximum payment path can be. --- diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 998c7a33d..4c254628d 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -282,9 +282,10 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) { let amt_msat = 5000; let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None); - let route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000, + let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000, nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&chan_upd_1_2, &chan_upd_2_3], &chanmon_cfgs[3].keys_manager); + route_params.payment_params.max_path_length = 18; let route = get_route(&nodes[0], &route_params).unwrap(); node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone())); diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 2aba2c757..9a207c9e5 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -10,12 +10,14 @@ use crate::blinded_path::BlindedHop; use crate::crypto::chacha20::ChaCha20; use crate::crypto::streams::ChaChaReader; +use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS; use crate::ln::channelmanager::{HTLCSource, RecipientOnionFields}; +use crate::ln::features::{ChannelFeatures, NodeFeatures}; use crate::ln::msgs; use crate::ln::types::{PaymentHash, PaymentPreimage}; use crate::ln::wire::Encode; use crate::routing::gossip::NetworkUpdate; -use crate::routing::router::{Path, RouteHop}; +use crate::routing::router::{Path, RouteHop, RouteParameters}; use crate::sign::NodeSigner; use crate::util::errors::{self, APIError}; use crate::util::logger::Logger; @@ -310,6 +312,77 @@ where Ok((cur_value_msat, cur_cltv)) } +pub(crate) const MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY: u64 = 100_000_000; + +pub(crate) fn set_max_path_length( + route_params: &mut RouteParameters, recipient_onion: &RecipientOnionFields, + keysend_preimage: Option, best_block_height: u32, +) -> Result<(), ()> { + const PAYLOAD_HMAC_LEN: usize = 32; + let unblinded_intermed_payload_len = msgs::OutboundOnionPayload::Forward { + short_channel_id: 42, + amt_to_forward: TOTAL_BITCOIN_SUPPLY_SATOSHIS, + outgoing_cltv_value: route_params.payment_params.max_total_cltv_expiry_delta, + } + .serialized_length() + .saturating_add(PAYLOAD_HMAC_LEN); + + const OVERPAY_ESTIMATE_MULTIPLER: u64 = 3; + let final_value_msat_with_overpay_buffer = core::cmp::max( + route_params.final_value_msat.saturating_mul(OVERPAY_ESTIMATE_MULTIPLER), + MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, + ); + + let blinded_tail_opt = route_params + .payment_params + .payee + .blinded_route_hints() + .iter() + .map(|(_, path)| path) + .max_by_key(|path| path.serialized_length()) + .map(|largest_path| BlindedTailHopIter { + hops: largest_path.blinded_hops.iter(), + blinding_point: largest_path.blinding_point, + final_value_msat: final_value_msat_with_overpay_buffer, + excess_final_cltv_expiry_delta: 0, + }); + + let unblinded_route_hop = RouteHop { + pubkey: PublicKey::from_slice(&[2; 33]).unwrap(), + node_features: NodeFeatures::empty(), + short_channel_id: 42, + channel_features: ChannelFeatures::empty(), + fee_msat: final_value_msat_with_overpay_buffer, + cltv_expiry_delta: route_params.payment_params.max_total_cltv_expiry_delta, + maybe_announced_channel: false, + }; + let mut num_reserved_bytes: usize = 0; + let build_payloads_res = build_onion_payloads_callback( + core::iter::once(&unblinded_route_hop), + blinded_tail_opt, + final_value_msat_with_overpay_buffer, + &recipient_onion, + best_block_height, + &keysend_preimage, + |_, payload| { + num_reserved_bytes = num_reserved_bytes + .saturating_add(payload.serialized_length()) + .saturating_add(PAYLOAD_HMAC_LEN); + }, + ); + debug_assert!(build_payloads_res.is_ok()); + + let max_path_length = 1300usize + .checked_sub(num_reserved_bytes) + .map(|p| p / unblinded_intermed_payload_len) + .and_then(|l| u8::try_from(l.saturating_add(1)).ok()) + .ok_or(())?; + + route_params.payment_params.max_path_length = + core::cmp::min(max_path_length, route_params.payment_params.max_path_length); + Ok(()) +} + /// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now /// the hops can be of variable length. pub(crate) const ONION_DATA_LEN: usize = 20 * 65; diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index c452a660e..b08a1e8a9 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -17,6 +17,7 @@ use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::events::{self, PaymentFailureReason}; use crate::ln::types::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId}; +use crate::ln::onion_utils; use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason}; use crate::offers::invoice::Bolt12Invoice; use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router}; @@ -421,6 +422,12 @@ pub enum RetryableSendFailure { /// [`Event::PaymentSent`]: crate::events::Event::PaymentSent /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed DuplicatePayment, + /// The [`RecipientOnionFields::payment_metadata`], [`RecipientOnionFields::custom_tlvs`], or + /// [`BlindedPath`]s provided are too large and caused us to exceed the maximum onion packet size + /// of 1300 bytes. + /// + /// [`BlindedPath`]: crate::blinded_path::BlindedPath + OnionPacketSizeExceeded, } /// If a payment fails to send with [`ChannelManager::send_payment_with_route`], it can be in one @@ -886,7 +893,7 @@ impl OutboundPayments { /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed fn send_payment_internal( &self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, - keysend_preimage: Option, retry_strategy: Retry, route_params: RouteParameters, + keysend_preimage: Option, retry_strategy: Retry, mut route_params: RouteParameters, router: &R, first_hops: Vec, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32, logger: &L, pending_events: &Mutex)>>, send_payment_along_path: SP, @@ -907,6 +914,15 @@ impl OutboundPayments { } } + onion_utils::set_max_path_length( + &mut route_params, &recipient_onion, keysend_preimage, best_block_height + ) + .map_err(|()| { + log_error!(logger, "Can't construct an onion packet without exceeding 1300-byte onion \ + hop_data length for payment with id {} and hash {}", payment_id, payment_hash); + RetryableSendFailure::OnionPacketSizeExceeded + })?; + let mut route = router.find_route_with_id( &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params, Some(&first_hops.iter().collect::>()), inflight_htlcs(),