X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Foutbound_payment.rs;h=f107f3b558395fe7ea9da8f8a8194f8f52a9f634;hb=0ecb4b093ac1134cbf06275cc48dd79ef7524774;hp=5270ed35d8835d6f240e8ae0fcd90b12e0851685;hpb=ec3aa494953c7d720370119f673e8e6b3a2155d5;p=rust-lightning diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 5270ed35..f107f3b5 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -13,10 +13,10 @@ use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, Secp256k1, SecretKey}; -use crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient}; +use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::events::{self, PaymentFailureReason}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; -use crate::ln::channelmanager::{ChannelDetails, HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, PaymentId}; +use crate::ln::channelmanager::{ChannelDetails, EventCompletionAction, HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, PaymentId}; use crate::ln::onion_utils::HTLCFailReason; use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router}; use crate::util::errors::APIError; @@ -60,6 +60,7 @@ pub(crate) enum PendingOutboundPayment { /// and add a pending payment that was already fulfilled. Fulfilled { session_privs: HashSet<[u8; 32]>, + /// Filled in for any payment which moved to `Fulfilled` on LDK 0.0.104 or later. payment_hash: Option, timer_ticks_without_htlcs: u8, }, @@ -487,7 +488,7 @@ impl OutboundPayments { retry_strategy: Retry, route_params: RouteParameters, router: &R, first_hops: Vec, compute_inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32, logger: &L, - pending_events: &Mutex>, send_payment_along_path: SP, + pending_events: &Mutex)>>, send_payment_along_path: SP, ) -> Result<(), RetryableSendFailure> where R::Target: Router, @@ -525,7 +526,7 @@ impl OutboundPayments { payment_id: PaymentId, retry_strategy: Retry, 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 + pending_events: &Mutex)>>, send_payment_along_path: SP ) -> Result where R::Target: Router, @@ -575,7 +576,8 @@ impl OutboundPayments { pub(super) fn check_retry_payments( &self, router: &R, first_hops: FH, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS, - best_block_height: u32, pending_events: &Mutex>, logger: &L, + best_block_height: u32, + pending_events: &Mutex)>>, logger: &L, send_payment_along_path: SP, ) where @@ -617,11 +619,11 @@ impl OutboundPayments { if !pmt.is_auto_retryable_now() && pmt.remaining_parts() == 0 { pmt.mark_abandoned(PaymentFailureReason::RetriesExhausted); if let PendingOutboundPayment::Abandoned { payment_hash, reason, .. } = pmt { - pending_events.lock().unwrap().push(events::Event::PaymentFailed { + pending_events.lock().unwrap().push_back((events::Event::PaymentFailed { payment_id: *pmt_id, payment_hash: *payment_hash, reason: *reason, - }); + }, None)); retain = false; } } @@ -645,7 +647,7 @@ impl OutboundPayments { keysend_preimage: Option, retry_strategy: Retry, 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, + pending_events: &Mutex)>>, send_payment_along_path: SP, ) -> Result<(), RetryableSendFailure> where R::Target: Router, @@ -686,7 +688,7 @@ impl OutboundPayments { &self, payment_hash: PaymentHash, payment_id: PaymentId, 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, + pending_events: &Mutex)>>, send_payment_along_path: &SP, ) where R::Target: Router, @@ -736,11 +738,11 @@ impl OutboundPayments { $payment.get_mut().mark_abandoned($reason); if let PendingOutboundPayment::Abandoned { reason, .. } = $payment.get() { if $payment.get().remaining_parts() == 0 { - pending_events.lock().unwrap().push(events::Event::PaymentFailed { + pending_events.lock().unwrap().push_back((events::Event::PaymentFailed { payment_id, payment_hash, reason: *reason, - }); + }, None)); $payment.remove(); } } @@ -808,7 +810,7 @@ impl OutboundPayments { &self, err: PaymentSendFailure, payment_id: PaymentId, payment_hash: PaymentHash, route: Route, 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, + pending_events: &Mutex)>>, send_payment_along_path: &SP, ) where R::Target: Router, @@ -851,7 +853,8 @@ impl OutboundPayments { fn push_path_failed_evs_and_scids>, L: Deref>( payment_id: PaymentId, payment_hash: PaymentHash, route_params: &mut RouteParameters, - paths: Vec, path_results: I, logger: &L, pending_events: &Mutex> + paths: Vec, path_results: I, logger: &L, + pending_events: &Mutex)>>, ) where L::Target: Logger { let mut events = pending_events.lock().unwrap(); debug_assert_eq!(paths.len(), path_results.len()); @@ -865,7 +868,7 @@ impl OutboundPayments { failed_scid = Some(scid); route_params.payment_params.previously_failed_channels.push(scid); } - events.push(events::Event::PaymentPathFailed { + events.push_back((events::Event::PaymentPathFailed { payment_id: Some(payment_id), payment_hash, payment_failed_permanently: false, @@ -876,7 +879,7 @@ impl OutboundPayments { error_code: None, #[cfg(test)] error_data: None, - }); + }, None)); } } } @@ -1112,7 +1115,9 @@ impl OutboundPayments { pub(super) fn claim_htlc( &self, payment_id: PaymentId, payment_preimage: PaymentPreimage, session_priv: SecretKey, - path: Path, from_onchain: bool, pending_events: &Mutex>, logger: &L + path: Path, from_onchain: bool, + pending_events: &Mutex)>>, + logger: &L, ) where L::Target: Logger { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); @@ -1122,14 +1127,12 @@ impl OutboundPayments { if !payment.get().is_fulfilled() { let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); let fee_paid_msat = payment.get().get_pending_fee_msat(); - pending_events.push( - events::Event::PaymentSent { - payment_id: Some(payment_id), - payment_preimage, - payment_hash, - fee_paid_msat, - } - ); + pending_events.push_back((events::Event::PaymentSent { + payment_id: Some(payment_id), + payment_preimage, + payment_hash, + fee_paid_msat, + }, None)); payment.get_mut().mark_fulfilled(); } @@ -1142,13 +1145,11 @@ impl OutboundPayments { // irrevocably fulfilled. if payment.get_mut().remove(&session_priv_bytes, Some(&path)) { let payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0).into_inner())); - pending_events.push( - events::Event::PaymentPathSuccessful { - payment_id, - payment_hash, - path, - } - ); + pending_events.push_back((events::Event::PaymentPathSuccessful { + payment_id, + payment_hash, + path, + }, None)); } } } else { @@ -1156,7 +1157,9 @@ impl OutboundPayments { } } - pub(super) fn finalize_claims(&self, sources: Vec, pending_events: &Mutex>) { + pub(super) fn finalize_claims(&self, sources: Vec, + pending_events: &Mutex)>>) + { let mut outbounds = self.pending_outbound_payments.lock().unwrap(); let mut pending_events = pending_events.lock().unwrap(); for source in sources { @@ -1166,20 +1169,22 @@ impl OutboundPayments { if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { assert!(payment.get().is_fulfilled()); if payment.get_mut().remove(&session_priv_bytes, None) { - pending_events.push( - events::Event::PaymentPathSuccessful { - payment_id, - payment_hash: payment.get().payment_hash(), - path, - } - ); + let payment_hash = payment.get().payment_hash(); + debug_assert!(payment_hash.is_some()); + pending_events.push_back((events::Event::PaymentPathSuccessful { + payment_id, + payment_hash, + path, + }, None)); } } } } } - pub(super) fn remove_stale_resolved_payments(&self, pending_events: &Mutex>) { + pub(super) fn remove_stale_resolved_payments(&self, + pending_events: &Mutex)>>) + { // If an outbound payment was completed, and no pending HTLCs remain, we should remove it // from the map. However, if we did that immediately when the last payment HTLC is claimed, // this could race the user making a duplicate send_payment call and our idempotency @@ -1193,7 +1198,7 @@ impl OutboundPayments { if let PendingOutboundPayment::Fulfilled { session_privs, timer_ticks_without_htlcs, .. } = payment { let mut no_remaining_entries = session_privs.is_empty(); if no_remaining_entries { - for ev in pending_events.iter() { + for (ev, _) in pending_events.iter() { match ev { events::Event::PaymentSent { payment_id: Some(ev_payment_id), .. } | events::Event::PaymentPathSuccessful { payment_id: ev_payment_id, .. } | @@ -1221,8 +1226,9 @@ impl OutboundPayments { // Returns a bool indicating whether a PendingHTLCsForwardable event should be generated. pub(super) fn fail_htlc( &self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, - path: &Path, session_priv: &SecretKey, payment_id: &PaymentId, probing_cookie_secret: [u8; 32], - secp_ctx: &Secp256k1, pending_events: &Mutex>, logger: &L + path: &Path, session_priv: &SecretKey, payment_id: &PaymentId, + probing_cookie_secret: [u8; 32], secp_ctx: &Secp256k1, + pending_events: &Mutex)>>, logger: &L, ) -> bool where L::Target: Logger { #[cfg(test)] let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_error.decode_onion_failure(secp_ctx, logger, &source); @@ -1334,24 +1340,25 @@ impl OutboundPayments { } }; let mut pending_events = pending_events.lock().unwrap(); - pending_events.push(path_failure); - if let Some(ev) = full_failure_ev { pending_events.push(ev); } + pending_events.push_back((path_failure, None)); + if let Some(ev) = full_failure_ev { pending_events.push_back((ev, None)); } pending_retry_ev } pub(super) fn abandon_payment( - &self, payment_id: PaymentId, reason: PaymentFailureReason, pending_events: &Mutex> + &self, payment_id: PaymentId, reason: PaymentFailureReason, + pending_events: &Mutex)>> ) { let mut outbounds = self.pending_outbound_payments.lock().unwrap(); if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { payment.get_mut().mark_abandoned(reason); if let PendingOutboundPayment::Abandoned { payment_hash, reason, .. } = payment.get() { if payment.get().remaining_parts() == 0 { - pending_events.lock().unwrap().push(events::Event::PaymentFailed { + pending_events.lock().unwrap().push_back((events::Event::PaymentFailed { payment_id, payment_hash: *payment_hash, reason: *reason, - }); + }, None)); payment.remove(); } } @@ -1435,6 +1442,8 @@ mod tests { use crate::util::errors::APIError; use crate::util::test_utils; + use alloc::collections::VecDeque; + #[test] #[cfg(feature = "std")] fn fails_paying_after_expiration() { @@ -1460,7 +1469,7 @@ mod tests { payment_params, final_value_msat: 0, }; - let pending_events = Mutex::new(Vec::new()); + let pending_events = Mutex::new(VecDeque::new()); if on_retry { outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]), None, &Route { paths: vec![], payment_params: None }, @@ -1472,7 +1481,7 @@ mod tests { &pending_events, &|_, _, _, _, _, _, _, _| Ok(())); let events = pending_events.lock().unwrap(); assert_eq!(events.len(), 1); - if let Event::PaymentFailed { ref reason, .. } = events[0] { + if let Event::PaymentFailed { ref reason, .. } = events[0].0 { assert_eq!(reason.unwrap(), PaymentFailureReason::PaymentExpired); } else { panic!("Unexpected event"); } } else { @@ -1508,7 +1517,7 @@ mod tests { router.expect_find_route(route_params.clone(), Err(LightningError { err: String::new(), action: ErrorAction::IgnoreError })); - let pending_events = Mutex::new(Vec::new()); + let pending_events = Mutex::new(VecDeque::new()); if on_retry { outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]), None, &Route { paths: vec![], payment_params: None }, @@ -1520,7 +1529,7 @@ mod tests { &pending_events, &|_, _, _, _, _, _, _, _| Ok(())); let events = pending_events.lock().unwrap(); assert_eq!(events.len(), 1); - if let Event::PaymentFailed { .. } = events[0] { } else { panic!("Unexpected event"); } + if let Event::PaymentFailed { .. } = events[0].0 { } else { panic!("Unexpected event"); } } else { let err = outbound_payments.send_payment( PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]), @@ -1570,7 +1579,7 @@ mod tests { // Ensure that a ChannelUnavailable error will result in blaming an scid in the // PaymentPathFailed event. - let pending_events = Mutex::new(Vec::new()); + let pending_events = Mutex::new(VecDeque::new()); outbound_payments.send_payment( PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(), PaymentId([0; 32]), Retry::Attempts(0), route_params.clone(), &&router, vec![], || InFlightHtlcs::new(), @@ -1581,11 +1590,11 @@ mod tests { assert_eq!(events.len(), 2); if let Event::PaymentPathFailed { short_channel_id, - failure: PathFailure::InitialSend { err: APIError::ChannelUnavailable { .. }}, .. } = events[0] + failure: PathFailure::InitialSend { err: APIError::ChannelUnavailable { .. }}, .. } = events[0].0 { assert_eq!(short_channel_id, Some(failed_scid)); } else { panic!("Unexpected event"); } - if let Event::PaymentFailed { .. } = events[1] { } else { panic!("Unexpected event"); } + if let Event::PaymentFailed { .. } = events[1].0 { } else { panic!("Unexpected event"); } events.clear(); core::mem::drop(events); @@ -1608,10 +1617,10 @@ mod tests { assert_eq!(events.len(), 2); if let Event::PaymentPathFailed { short_channel_id, - failure: PathFailure::InitialSend { err: APIError::APIMisuseError { .. }}, .. } = events[0] + failure: PathFailure::InitialSend { err: APIError::APIMisuseError { .. }}, .. } = events[0].0 { assert_eq!(short_channel_id, None); } else { panic!("Unexpected event"); } - if let Event::PaymentFailed { .. } = events[1] { } else { panic!("Unexpected event"); } + if let Event::PaymentFailed { .. } = events[1].0 { } else { panic!("Unexpected event"); } } }