X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Foutbound_payment.rs;h=a4def55cfeb5edb8dd19390334a0caaa7a1e9258;hb=948ebc67f01a6b17c04687c8c4b35431d01192e3;hp=95ad59e634faf41bf461855255b10ec5574cdcb8;hpb=e64ebe8608a3efdf630b288a7bddddf916f0cf86;p=rust-lightning diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 95ad59e6..a4def55c 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -13,7 +13,7 @@ use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, Secp256k1, SecretKey}; -use crate::chain::keysinterface::{KeysInterface, Recipient}; +use crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient}; use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channelmanager::{HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, PaymentId}; use crate::ln::msgs::DecodeError; @@ -22,9 +22,14 @@ use crate::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters use crate::util::errors::APIError; use crate::util::events; use crate::util::logger::Logger; +use crate::util::time::Time; +#[cfg(all(not(feature = "no-std"), test))] +use crate::util::time::tests::SinceEpoch; use core::cmp; +use core::fmt::{self, Display, Formatter}; use core::ops::Deref; + use crate::prelude::*; use crate::sync::Mutex; @@ -60,7 +65,7 @@ pub(crate) enum PendingOutboundPayment { /// `PaymentPathFailed` events with `all_paths_failed` can be pending at once, confusing a /// downstream event handler as to when a payment has actually failed. /// - /// (1) https://github.com/lightningdevkit/rust-lightning/issues/1164 + /// (1) Abandoned { session_privs: HashSet<[u8; 32]>, payment_hash: PaymentHash, @@ -182,6 +187,48 @@ impl PendingOutboundPayment { } } +pub(crate) type PaymentAttempts = PaymentAttemptsUsingTime; + +/// Storing minimal payment attempts information required for determining if a outbound payment can +/// be retried. +pub(crate) struct PaymentAttemptsUsingTime { + /// This count will be incremented only after the result of the attempt is known. When it's 0, + /// it means the result of the first attempt is not known yet. + pub(crate) count: usize, + /// This field is only used when retry is `Retry::Timeout` which is only build with feature std + first_attempted_at: T +} + +#[cfg(not(any(feature = "no-std", test)))] +type ConfiguredTime = std::time::Instant; +#[cfg(feature = "no-std")] +type ConfiguredTime = crate::util::time::Eternity; +#[cfg(all(not(feature = "no-std"), test))] +type ConfiguredTime = SinceEpoch; + +impl PaymentAttemptsUsingTime { + pub(crate) fn new() -> Self { + PaymentAttemptsUsingTime { + count: 0, + first_attempted_at: T::now() + } + } +} + +impl Display for PaymentAttemptsUsingTime { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + #[cfg(feature = "no-std")] + return write!(f, "attempts: {}", self.count); + #[cfg(not(feature = "no-std"))] + return write!( + f, + "attempts: {}, duration: {}s", + self.count, + T::now().duration_since(self.first_attempted_at).as_secs() + ); + } +} + /// If a payment fails to send, it can be in one of several states. This enum is returned as the /// Err() type describing which state the payment is in, see the description of individual enum /// states for more. @@ -271,47 +318,51 @@ impl OutboundPayments { } } - pub(super) fn send_payment_with_route( + pub(super) fn send_payment_with_route( &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option, - payment_id: PaymentId, keys_manager: &K, best_block_height: u32, send_payment_along_path: F + payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32, + send_payment_along_path: F ) -> Result<(), PaymentSendFailure> where - K::Target: KeysInterface, + ES::Target: EntropySource, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { - let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret, payment_id, route, keys_manager, best_block_height)?; - self.send_payment_internal(route, payment_hash, payment_secret, None, payment_id, None, onion_session_privs, keys_manager, best_block_height, send_payment_along_path) + let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret, payment_id, route, entropy_source, best_block_height)?; + self.send_payment_internal(route, payment_hash, payment_secret, None, payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path) } - pub(super) fn send_spontaneous_payment( + pub(super) fn send_spontaneous_payment( &self, route: &Route, payment_preimage: Option, payment_id: PaymentId, - keys_manager: &K, best_block_height: u32, send_payment_along_path: F + entropy_source: &ES, node_signer: &NS, best_block_height: u32, send_payment_along_path: F ) -> Result where - K::Target: KeysInterface, + ES::Target: EntropySource, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { let preimage = match payment_preimage { Some(p) => p, - None => PaymentPreimage(keys_manager.get_secure_random_bytes()), + None => PaymentPreimage(entropy_source.get_secure_random_bytes()), }; let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner()); - let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, keys_manager, best_block_height)?; + let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, entropy_source, best_block_height)?; - match self.send_payment_internal(route, payment_hash, &None, Some(preimage), payment_id, None, onion_session_privs, keys_manager, best_block_height, send_payment_along_path) { + match self.send_payment_internal(route, payment_hash, &None, Some(preimage), payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path) { Ok(()) => Ok(payment_hash), Err(e) => Err(e) } } - pub(super) fn retry_payment_with_route( - &self, route: &Route, payment_id: PaymentId, keys_manager: &K, best_block_height: u32, + pub(super) fn retry_payment_with_route( + &self, route: &Route, payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32, send_payment_along_path: F ) -> Result<(), PaymentSendFailure> where - K::Target: KeysInterface, + ES::Target: EntropySource, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { @@ -326,7 +377,7 @@ impl OutboundPayments { let mut onion_session_privs = Vec::with_capacity(route.paths.len()); for _ in 0..route.paths.len() { - onion_session_privs.push(keys_manager.get_secure_random_bytes()); + onion_session_privs.push(entropy_source.get_secure_random_bytes()); } let (total_msat, payment_hash, payment_secret) = { @@ -372,19 +423,20 @@ impl OutboundPayments { })), } }; - self.send_payment_internal(route, payment_hash, &payment_secret, None, payment_id, Some(total_msat), onion_session_privs, keys_manager, best_block_height, send_payment_along_path) + self.send_payment_internal(route, payment_hash, &payment_secret, None, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, send_payment_along_path) } - pub(super) fn send_probe( - &self, hops: Vec, probing_cookie_secret: [u8; 32], keys_manager: &K, - best_block_height: u32, send_payment_along_path: F + pub(super) fn send_probe( + &self, hops: Vec, probing_cookie_secret: [u8; 32], entropy_source: &ES, + node_signer: &NS, best_block_height: u32, send_payment_along_path: F ) -> Result<(PaymentHash, PaymentId), PaymentSendFailure> where - K::Target: KeysInterface, + ES::Target: EntropySource, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { - let payment_id = PaymentId(keys_manager.get_secure_random_bytes()); + let payment_id = PaymentId(entropy_source.get_secure_random_bytes()); let payment_hash = probing_cookie_from_id(&payment_id, probing_cookie_secret); @@ -395,21 +447,29 @@ impl OutboundPayments { } let route = Route { paths: vec![hops], payment_params: None }; - let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, keys_manager, best_block_height)?; + let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, entropy_source, best_block_height)?; - match self.send_payment_internal(&route, payment_hash, &None, None, payment_id, None, onion_session_privs, keys_manager, best_block_height, send_payment_along_path) { + match self.send_payment_internal(&route, payment_hash, &None, None, payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path) { Ok(()) => Ok((payment_hash, payment_id)), Err(e) => Err(e) } } - pub(super) fn add_new_pending_payment( + #[cfg(test)] + pub(super) fn test_add_new_pending_payment( + &self, payment_hash: PaymentHash, payment_secret: Option, payment_id: PaymentId, + route: &Route, entropy_source: &ES, best_block_height: u32 + ) -> Result, PaymentSendFailure> where ES::Target: EntropySource { + self.add_new_pending_payment(payment_hash, payment_secret, payment_id, route, entropy_source, best_block_height) + } + + pub(super) fn add_new_pending_payment( &self, payment_hash: PaymentHash, payment_secret: Option, payment_id: PaymentId, - route: &Route, keys_manager: &K, best_block_height: u32 - ) -> Result, PaymentSendFailure> where K::Target: KeysInterface { + route: &Route, entropy_source: &ES, best_block_height: u32 + ) -> Result, PaymentSendFailure> where ES::Target: EntropySource { let mut onion_session_privs = Vec::with_capacity(route.paths.len()); for _ in 0..route.paths.len() { - onion_session_privs.push(keys_manager.get_secure_random_bytes()); + onion_session_privs.push(entropy_source.get_secure_random_bytes()); } let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap(); @@ -435,13 +495,14 @@ impl OutboundPayments { } } - fn send_payment_internal( + fn send_payment_internal( &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, - onion_session_privs: Vec<[u8; 32]>, keys_manager: &K, best_block_height: u32, - send_payment_along_path: F) -> Result<(), PaymentSendFailure> + onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32, + send_payment_along_path: F + ) -> Result<(), PaymentSendFailure> where - K::Target: KeysInterface, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { @@ -452,7 +513,7 @@ impl OutboundPayments { return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError{err: "Payment secret is required for multi-path payments".to_string()})); } let mut total_value = 0; - let our_node_id = keys_manager.get_node_id(Recipient::Node).unwrap(); // TODO no unwrap + let our_node_id = node_signer.get_node_id(Recipient::Node).unwrap(); // TODO no unwrap let mut path_errs = Vec::with_capacity(route.paths.len()); 'path_check: for path in route.paths.iter() { if path.len() < 1 || path.len() > 20 { @@ -544,25 +605,26 @@ impl OutboundPayments { } #[cfg(test)] - pub(super) fn test_send_payment_internal( + pub(super) fn test_send_payment_internal( &self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option, keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, - onion_session_privs: Vec<[u8; 32]>, keys_manager: &K, best_block_height: u32, - send_payment_along_path: F) -> Result<(), PaymentSendFailure> + onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32, + send_payment_along_path: F + ) -> Result<(), PaymentSendFailure> where - K::Target: KeysInterface, + NS::Target: NodeSigner, F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { self.send_payment_internal(route, payment_hash, payment_secret, keysend_preimage, payment_id, - recv_value_msat, onion_session_privs, keys_manager, best_block_height, + recv_value_msat, onion_session_privs, node_signer, best_block_height, send_payment_along_path) } pub(super) fn claim_htlc( &self, payment_id: PaymentId, payment_preimage: PaymentPreimage, session_priv: SecretKey, - path: Vec, from_onchain: bool, pending_events: &Mutex>, logger: &L) - where L::Target: Logger { + path: Vec, 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[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); @@ -671,8 +733,8 @@ impl OutboundPayments { &self, source: &HTLCSource, payment_hash: &PaymentHash, onion_error: &HTLCFailReason, path: &Vec, session_priv: &SecretKey, payment_id: &PaymentId, payment_params: &Option, probing_cookie_secret: [u8; 32], - secp_ctx: &Secp256k1, pending_events: &Mutex>, logger: &L) - where L::Target: Logger { + secp_ctx: &Secp256k1, pending_events: &Mutex>, logger: &L + ) where L::Target: Logger { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); @@ -712,9 +774,9 @@ impl OutboundPayments { log_trace!(logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0)); let path_failure = { - #[cfg(test)] + #[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); - #[cfg(not(test))] + #[cfg(not(test))] let (network_update, short_channel_id, payment_retryable, _, _) = onion_error.decode_onion_failure(secp_ctx, logger, &source); if payment_is_probe(payment_hash, &payment_id, probing_cookie_secret) {