X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=e0bcd089c4cf00043739cbdb4c7897589acacbee;hb=1ce922c631aac879b3569047a8f17e2a5df5e76a;hp=da6f6d958b145f5b1cb13bc85dfc1c66c12bfa53;hpb=31975c5994c8daca5b69c7c3b7d5466409ae8c2d;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index da6f6d95..e0bcd089 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -413,6 +413,9 @@ struct PeerState { /// /// For users who don't want to bother doing their own payment preimage storage, we also store that /// here. +/// +/// Note that this struct will be removed entirely soon, in favor of storing no inbound payment data +/// and instead encoding it in the payment secret. struct PendingInboundPayment { /// The payment secret that the sender must use for us to accept this payment payment_secret: PaymentSecret, @@ -449,6 +452,7 @@ pub(crate) enum PendingOutboundPayment { /// and add a pending payment that was already fulfilled. Fulfilled { session_privs: HashSet<[u8; 32]>, + payment_hash: Option, }, } @@ -472,15 +476,24 @@ impl PendingOutboundPayment { } } + fn payment_hash(&self) -> Option { + match self { + PendingOutboundPayment::Legacy { .. } => None, + PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash), + PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash, + } + } + fn mark_fulfilled(&mut self) { let mut session_privs = HashSet::new(); core::mem::swap(&mut session_privs, match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs } + PendingOutboundPayment::Fulfilled { session_privs, .. } => session_privs }); - *self = PendingOutboundPayment::Fulfilled { session_privs }; + let payment_hash = self.payment_hash(); + *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash }; } /// panics if path is None and !self.is_fulfilled @@ -488,7 +501,7 @@ impl PendingOutboundPayment { let remove_res = match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs } => { + PendingOutboundPayment::Fulfilled { session_privs, .. } => { session_privs.remove(session_priv) } }; @@ -529,7 +542,7 @@ impl PendingOutboundPayment { match self { PendingOutboundPayment::Legacy { session_privs } | PendingOutboundPayment::Retryable { session_privs, .. } | - PendingOutboundPayment::Fulfilled { session_privs } => { + PendingOutboundPayment::Fulfilled { session_privs, .. } => { session_privs.len() } } @@ -2887,7 +2900,6 @@ impl ChannelMana purpose: events::PaymentPurpose::InvoicePayment { payment_preimage: inbound_payment.get().payment_preimage, payment_secret: payment_data.payment_secret, - user_payment_id: inbound_payment.get().user_payment_id, }, amt: total_value, }); @@ -3491,14 +3503,23 @@ impl ChannelMana } fn finalize_claims(&self, mut sources: Vec) { + let mut pending_events = self.pending_events.lock().unwrap(); for source in sources.drain(..) { - if let HTLCSource::OutboundRoute { session_priv, payment_id, .. } = source { + if let HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } = source { let mut session_priv_bytes = [0; 32]; session_priv_bytes.copy_from_slice(&session_priv[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { assert!(payment.get().is_fulfilled()); - payment.get_mut().remove(&session_priv_bytes, None); + if payment.get_mut().remove(&session_priv_bytes, None) { + pending_events.push( + events::Event::PaymentPathSuccessful { + payment_id, + payment_hash: payment.get().payment_hash(), + path, + } + ); + } if payment.get().remaining_parts() == 0 { payment.remove(); } @@ -3515,9 +3536,21 @@ impl ChannelMana session_priv_bytes.copy_from_slice(&session_priv[..]); let mut outbounds = self.pending_outbound_payments.lock().unwrap(); if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(payment_id) { - let found_payment = !payment.get().is_fulfilled(); - let fee_paid_msat = payment.get().get_pending_fee_msat(); - payment.get_mut().mark_fulfilled(); + let mut pending_events = self.pending_events.lock().unwrap(); + 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, + } + ); + payment.get_mut().mark_fulfilled(); + } + if from_onchain { // We currently immediately remove HTLCs which were fulfilled on-chain. // This could potentially lead to removing a pending payment too early, @@ -3525,22 +3558,21 @@ impl ChannelMana // restart. // TODO: We should have a second monitor event that informs us of payments // irrevocably fulfilled. - payment.get_mut().remove(&session_priv_bytes, Some(&path)); + 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, + } + ); + } + if payment.get().remaining_parts() == 0 { payment.remove(); } } - if found_payment { - let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); - self.pending_events.lock().unwrap().push( - events::Event::PaymentSent { - payment_id: Some(payment_id), - payment_preimage, - payment_hash: payment_hash, - fee_paid_msat, - } - ); - } } else { log_trace!(self.logger, "Received duplicative fulfill for HTLC with payment_preimage {}", log_bytes!(payment_preimage.0)); } @@ -4523,7 +4555,7 @@ impl ChannelMana } } - fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result { + fn set_payment_hash_secret_map(&self, payment_hash: PaymentHash, payment_preimage: Option, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { assert!(invoice_expiry_delta_secs <= 60*60*24*365); // Sadly bitcoin timestamps are u32s, so panic before 2106 let payment_secret = PaymentSecret(self.keys_manager.get_secure_random_bytes()); @@ -4533,7 +4565,8 @@ impl ChannelMana match payment_secrets.entry(payment_hash) { hash_map::Entry::Vacant(e) => { e.insert(PendingInboundPayment { - payment_secret, min_value_msat, user_payment_id, payment_preimage, + payment_secret, min_value_msat, payment_preimage, + user_payment_id: 0, // For compatibility with version 0.0.103 and earlier // We assume that highest_seen_timestamp is pretty close to the current time - // its updated when we receive a new block with the maximum time we've seen in // a header. It should never be more than two hours in the future. @@ -4565,12 +4598,12 @@ impl ChannelMana /// [`PaymentReceived`]: events::Event::PaymentReceived /// [`PaymentReceived::payment_preimage`]: events::Event::PaymentReceived::payment_preimage /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash - pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> (PaymentHash, PaymentSecret) { + pub fn create_inbound_payment(&self, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> (PaymentHash, PaymentSecret) { let payment_preimage = PaymentPreimage(self.keys_manager.get_secure_random_bytes()); let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); (payment_hash, - self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs, user_payment_id) + self.set_payment_hash_secret_map(payment_hash, Some(payment_preimage), min_value_msat, invoice_expiry_delta_secs) .expect("RNG Generated Duplicate PaymentHash")) } @@ -4584,12 +4617,6 @@ impl ChannelMana /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This /// method may return an Err if another payment with the same payment_hash is still pending. /// - /// `user_payment_id` will be provided back in [`PaymentPurpose::InvoicePayment::user_payment_id`] events to - /// allow tracking of which events correspond with which calls to this and - /// [`create_inbound_payment`]. `user_payment_id` has no meaning inside of LDK, it is simply - /// copied to events and otherwise ignored. It may be used to correlate PaymentReceived events - /// with invoice metadata stored elsewhere. - /// /// `min_value_msat` should be set if the invoice being generated contains a value. Any payment /// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat` /// before a [`PaymentReceived`] event will be generated, ensuring that we do not provide the @@ -4618,9 +4645,8 @@ impl ChannelMana /// /// [`create_inbound_payment`]: Self::create_inbound_payment /// [`PaymentReceived`]: events::Event::PaymentReceived - /// [`PaymentPurpose::InvoicePayment::user_payment_id`]: events::PaymentPurpose::InvoicePayment::user_payment_id - pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32, user_payment_id: u64) -> Result { - self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs, user_payment_id) + pub fn create_inbound_payment_for_hash(&self, payment_hash: PaymentHash, min_value_msat: Option, invoice_expiry_delta_secs: u32) -> Result { + self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs) } #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] @@ -4635,6 +4661,11 @@ impl ChannelMana pub fn has_pending_payments(&self) -> bool { !self.pending_outbound_payments.lock().unwrap().is_empty() } + + #[cfg(test)] + pub fn clear_pending_payments(&self) { + self.pending_outbound_payments.lock().unwrap().clear() + } } impl MessageSendEventsProvider for ChannelManager @@ -5559,6 +5590,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, }, (1, Fulfilled) => { (0, session_privs, required), + (1, payment_hash, option), }, (2, Retryable) => { (0, session_privs, required), @@ -5874,6 +5906,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> reason: ClosureReason::OutdatedChannelManager }); } else { + log_info!(args.logger, "Successfully loaded channel {}", log_bytes!(channel.channel_id())); if let Some(short_channel_id) = channel.get_short_channel_id() { short_to_id.insert(short_channel_id, channel.channel_id()); } @@ -5891,6 +5924,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> for (ref funding_txo, ref mut monitor) in args.channel_monitors.iter_mut() { if !funding_txo_set.contains(funding_txo) { + log_info!(args.logger, "Broadcasting latest holder commitment transaction for closed channel {}", log_bytes!(funding_txo.to_channel_id())); monitor.broadcast_latest_holder_commitment_txn(&args.tx_broadcaster, &args.logger); } } @@ -6325,9 +6359,10 @@ mod tests { nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_third_raa); check_added_monitors!(nodes[0], 1); - // Note that successful MPP payments will generate 1 event upon the first path's success. No - // further events will be generated for subsequence path successes. + // Note that successful MPP payments will generate a single PaymentSent event upon the first + // path's success and a PaymentPathSuccessful event for each path's success. let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 3); match events[0] { Event::PaymentSent { payment_id: ref id, payment_preimage: ref preimage, payment_hash: ref hash, .. } => { assert_eq!(Some(payment_id), *id); @@ -6336,6 +6371,22 @@ mod tests { }, _ => panic!("Unexpected event"), } + match events[1] { + Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => { + assert_eq!(payment_id, *actual_payment_id); + assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap()); + assert_eq!(route.paths[0], *path); + }, + _ => panic!("Unexpected event"), + } + match events[2] { + Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => { + assert_eq!(payment_id, *actual_payment_id); + assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap()); + assert_eq!(route.paths[0], *path); + }, + _ => panic!("Unexpected event"), + } } #[test] @@ -6680,7 +6731,7 @@ pub mod bench { payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes()); payment_count += 1; let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); - let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, 0).unwrap(); + let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200).unwrap(); $node_a.send_payment(&route, payment_hash, &Some(payment_secret)).unwrap(); let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap());