X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Foutbound_payment.rs;h=b05d6f3f7290110b5aed103faef370203350a8fc;hb=ad91fcd510d7620df438a4cf59f7ed7b080adb19;hp=e1748dca7f2ac11978035b2b44c4b66f8a2973d0;hpb=c2bbfffb1eb249c2c422cf2e9ccac97a34275f7a;p=rust-lightning diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index e1748dca..b05d6f3f 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -19,11 +19,11 @@ use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, PaymentId}; use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason}; use crate::offers::invoice::Bolt12Invoice; -use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router}; +use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router}; use crate::util::errors::APIError; use crate::util::logger::Logger; use crate::util::time::Time; -#[cfg(all(not(feature = "no-std"), test))] +#[cfg(all(feature = "std", test))] use crate::util::time::tests::SinceEpoch; use crate::util::ser::ReadableArgs; @@ -129,6 +129,11 @@ impl PendingOutboundPayment { params.previously_failed_channels.push(scid); } } + pub fn insert_previously_failed_blinded_path(&mut self, blinded_tail: &BlindedTail) { + if let PendingOutboundPayment::Retryable { payment_params: Some(params), .. } = self { + params.insert_previously_failed_blinded_path(blinded_tail); + } + } fn is_awaiting_invoice(&self) -> bool { match self { PendingOutboundPayment::AwaitingInvoice { .. } => true, @@ -166,7 +171,7 @@ impl PendingOutboundPayment { } fn mark_fulfilled(&mut self) { - let mut session_privs = HashSet::new(); + let mut session_privs = new_hash_set(); core::mem::swap(&mut session_privs, match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | @@ -181,7 +186,7 @@ impl PendingOutboundPayment { fn mark_abandoned(&mut self, reason: PaymentFailureReason) { if let PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } = self { - let mut our_session_privs = HashSet::new(); + let mut our_session_privs = new_hash_set(); core::mem::swap(&mut our_session_privs, session_privs); *self = PendingOutboundPayment::Abandoned { session_privs: our_session_privs, @@ -190,7 +195,7 @@ impl PendingOutboundPayment { }; } else if let PendingOutboundPayment::InvoiceReceived { payment_hash, .. } = self { *self = PendingOutboundPayment::Abandoned { - session_privs: HashSet::new(), + session_privs: new_hash_set(), payment_hash: *payment_hash, reason: Some(reason) }; @@ -243,7 +248,7 @@ impl PendingOutboundPayment { if insert_res { if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, - ref mut remaining_max_total_routing_fee_msat, .. + ref mut remaining_max_total_routing_fee_msat, .. } = self { *pending_amt_msat += path.final_value_msat(); let path_fee_msat = path.fee_msat(); @@ -282,7 +287,7 @@ pub enum Retry { /// retry, and may retry multiple failed HTLCs at once if they failed around the same time and /// were retried along a route from a single call to [`Router::find_route_with_id`]. Attempts(u32), - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] /// Time elapsed before abandoning retries for a payment. At least one attempt at payment is made; /// see [`PaymentParameters::expiry_time`] to avoid any attempt at payment after a specific time. /// @@ -290,13 +295,13 @@ pub enum Retry { Timeout(core::time::Duration), } -#[cfg(feature = "no-std")] +#[cfg(not(feature = "std"))] impl_writeable_tlv_based_enum!(Retry, ; (0, Attempts) ); -#[cfg(not(feature = "no-std"))] +#[cfg(feature = "std")] impl_writeable_tlv_based_enum!(Retry, ; (0, Attempts), @@ -309,10 +314,10 @@ impl Retry { (Retry::Attempts(max_retry_count), PaymentAttempts { count, .. }) => { max_retry_count > count }, - #[cfg(all(not(feature = "no-std"), not(test)))] + #[cfg(all(feature = "std", not(test)))] (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) => *max_duration >= crate::util::time::MonotonicTime::now().duration_since(*first_attempted_at), - #[cfg(all(not(feature = "no-std"), test))] + #[cfg(all(feature = "std", test))] (Retry::Timeout(max_duration), PaymentAttempts { first_attempted_at, .. }) => *max_duration >= SinceEpoch::now().duration_since(*first_attempted_at), } @@ -338,27 +343,27 @@ pub(crate) struct PaymentAttemptsUsingTime { /// it means the result of the first attempt is not known yet. pub(crate) count: u32, /// This field is only used when retry is `Retry::Timeout` which is only build with feature std - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] first_attempted_at: T, - #[cfg(feature = "no-std")] + #[cfg(not(feature = "std"))] phantom: core::marker::PhantomData, } -#[cfg(not(any(feature = "no-std", test)))] -type ConfiguredTime = crate::util::time::MonotonicTime; -#[cfg(feature = "no-std")] +#[cfg(not(feature = "std"))] type ConfiguredTime = crate::util::time::Eternity; -#[cfg(all(not(feature = "no-std"), test))] +#[cfg(all(feature = "std", not(test)))] +type ConfiguredTime = crate::util::time::MonotonicTime; +#[cfg(all(feature = "std", test))] type ConfiguredTime = SinceEpoch; impl PaymentAttemptsUsingTime { pub(crate) fn new() -> Self { PaymentAttemptsUsingTime { count: 0, - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] first_attempted_at: T::now(), - #[cfg(feature = "no-std")] + #[cfg(not(feature = "std"))] phantom: core::marker::PhantomData, } } @@ -366,9 +371,9 @@ impl PaymentAttemptsUsingTime { impl Display for PaymentAttemptsUsingTime { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - #[cfg(feature = "no-std")] + #[cfg(not(feature = "std"))] return write!(f, "attempts: {}", self.count); - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] return write!( f, "attempts: {}, duration: {}s", @@ -670,7 +675,7 @@ pub(super) struct OutboundPayments { impl OutboundPayments { pub(super) fn new() -> Self { Self { - pending_outbound_payments: Mutex::new(HashMap::new()), + pending_outbound_payments: Mutex::new(new_hash_map()), retry_lock: Mutex::new(()), } } @@ -1263,7 +1268,7 @@ impl OutboundPayments { retry_strategy, attempts: PaymentAttempts::new(), payment_params, - session_privs: HashSet::new(), + session_privs: new_hash_set(), pending_amt_msat: 0, pending_fee_msat: Some(0), payment_hash, @@ -1604,11 +1609,12 @@ impl OutboundPayments { #[cfg(test)] let DecodedOnionFailure { network_update, short_channel_id, payment_failed_permanently, onion_error_code, - onion_error_data + onion_error_data, failed_within_blinded_path } = onion_error.decode_onion_failure(secp_ctx, logger, &source); #[cfg(not(test))] - let DecodedOnionFailure { network_update, short_channel_id, payment_failed_permanently } = - onion_error.decode_onion_failure(secp_ctx, logger, &source); + let DecodedOnionFailure { + network_update, short_channel_id, payment_failed_permanently, failed_within_blinded_path + } = onion_error.decode_onion_failure(secp_ctx, logger, &source); let payment_is_probe = payment_is_probe(payment_hash, &payment_id, probing_cookie_secret); let mut session_priv_bytes = [0; 32]; @@ -1647,6 +1653,12 @@ impl OutboundPayments { // next-hop is needlessly blaming us! payment.get_mut().insert_previously_failed_scid(scid); } + if failed_within_blinded_path { + debug_assert!(short_channel_id.is_none()); + if let Some(bt) = &path.blinded_tail { + payment.get_mut().insert_previously_failed_blinded_path(&bt); + } else { debug_assert!(false); } + } if payment_is_probe || !is_retryable_now || payment_failed_permanently { let reason = if payment_failed_permanently { @@ -1876,7 +1888,7 @@ mod tests { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); @@ -1920,7 +1932,7 @@ mod tests { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); @@ -1959,7 +1971,7 @@ mod tests { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); @@ -2166,7 +2178,7 @@ mod tests { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); let pending_events = Mutex::new(VecDeque::new()); @@ -2217,7 +2229,7 @@ mod tests { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); let pending_events = Mutex::new(VecDeque::new()); @@ -2271,71 +2283,12 @@ mod tests { assert!(pending_events.lock().unwrap().is_empty()); } - #[test] - fn fails_paying_for_bolt12_invoice() { - let logger = test_utils::TestLogger::new(); - let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); - let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); - let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); - - let pending_events = Mutex::new(VecDeque::new()); - let outbound_payments = OutboundPayments::new(); - let payment_id = PaymentId([0; 32]); - let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100)); - - let invoice = OfferBuilder::new("foo".into(), recipient_pubkey()) - .amount_msats(1000) - .build().unwrap() - .request_invoice(vec![1; 32], payer_pubkey()).unwrap() - .build().unwrap() - .sign(payer_sign).unwrap() - .respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap() - .build().unwrap() - .sign(recipient_sign).unwrap(); - - assert!( - outbound_payments.add_new_awaiting_invoice( - payment_id, expiration, Retry::Attempts(0), - Some(invoice.amount_msats() / 100 + 50_000) - ).is_ok() - ); - assert!(outbound_payments.has_pending_payments()); - - let route_params = RouteParameters::from_payment_params_and_value( - PaymentParameters::from_bolt12_invoice(&invoice), - invoice.amount_msats(), - ); - router.expect_find_route( - route_params.clone(), Ok(Route { paths: vec![], route_params: Some(route_params) }) - ); - - assert_eq!( - outbound_payments.send_payment_for_bolt12_invoice( - &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, - &&keys_manager, 0, &&logger, &pending_events, |_| panic!() - ), - Ok(()), - ); - assert!(!outbound_payments.has_pending_payments()); - - let payment_hash = invoice.payment_hash(); - let reason = Some(PaymentFailureReason::UnexpectedError); - - assert!(!pending_events.lock().unwrap().is_empty()); - assert_eq!( - pending_events.lock().unwrap().pop_front(), - Some((Event::PaymentFailed { payment_id, payment_hash, reason }, None)), - ); - assert!(pending_events.lock().unwrap().is_empty()); - } - #[test] fn sends_payment_for_bolt12_invoice() { let logger = test_utils::TestLogger::new(); let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger)); let scorer = RwLock::new(test_utils::TestScorer::new()); - let router = test_utils::TestRouter::new(network_graph, &scorer); + let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); let pending_events = Mutex::new(VecDeque::new());