X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=8f68a1d68126c9120679297c9aea4e77f0efb2cd;hb=581ea7c6edef48be22137f85b6e6e09446d58396;hp=742dc0344c252c463861a43b6a7261643691990a;hpb=e99e6ab562af9b9a7e0f2d0dc1fee3dd09bb4082;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 742dc034..8f68a1d6 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -237,7 +237,12 @@ impl From<&ClaimableHTLC> for events::ClaimedHTLC { /// /// This is not exported to bindings users as we just use [u8; 32] directly #[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] -pub struct PaymentId(pub [u8; 32]); +pub struct PaymentId(pub [u8; Self::LENGTH]); + +impl PaymentId { + /// Number of bytes in the id. + pub const LENGTH: usize = 32; +} impl Writeable for PaymentId { fn write(&self, w: &mut W) -> Result<(), io::Error> { @@ -1338,7 +1343,7 @@ pub(crate) const MPP_TIMEOUT_TICKS: u8 = 3; /// The number of ticks of [`ChannelManager::timer_tick_occurred`] until we time-out the /// idempotency of payments by [`PaymentId`]. See -/// [`OutboundPayments::remove_stale_resolved_payments`]. +/// [`OutboundPayments::remove_stale_payments`]. pub(crate) const IDEMPOTENCY_TIMEOUT_TICKS: u8 = 7; /// The number of ticks of [`ChannelManager::timer_tick_occurred`] where a peer is disconnected @@ -1683,6 +1688,11 @@ pub enum ChannelShutdownState { /// These include payments that have yet to find a successful path, or have unresolved HTLCs. #[derive(Debug, PartialEq)] pub enum RecentPaymentDetails { + /// When an invoice was requested but not yet received, and thus a payment has not been sent. + AwaitingInvoice { + /// Identifier for the payment to ensure idempotency. + payment_id: PaymentId, + }, /// When a payment is still being sent and awaiting successful delivery. Pending { /// Hash of the payment that is currently being sent but has yet to be fulfilled or @@ -2414,7 +2424,10 @@ where /// [`Event::PaymentSent`]: events::Event::PaymentSent pub fn list_recent_payments(&self) -> Vec { self.pending_outbound_payments.pending_outbound_payments.lock().unwrap().iter() - .filter_map(|(_, pending_outbound_payment)| match pending_outbound_payment { + .filter_map(|(payment_id, pending_outbound_payment)| match pending_outbound_payment { + PendingOutboundPayment::AwaitingInvoice { .. } => { + Some(RecentPaymentDetails::AwaitingInvoice { payment_id: *payment_id }) + }, PendingOutboundPayment::Retryable { payment_hash, total_msat, .. } => { Some(RecentPaymentDetails::Pending { payment_hash: *payment_hash, @@ -3376,10 +3389,12 @@ where } - /// Signals that no further retries for the given payment should occur. Useful if you have a + /// Signals that no further attempts for the given payment should occur. Useful if you have a /// pending outbound payment with retries remaining, but wish to stop retrying the payment before /// retries are exhausted. /// + /// # Event Generation + /// /// If no [`Event::PaymentFailed`] event had been generated before, one will be generated as soon /// as there are no remaining pending HTLCs for this payment. /// @@ -3387,11 +3402,19 @@ where /// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to /// determine the ultimate status of a payment. /// - /// If an [`Event::PaymentFailed`] event is generated and we restart without this - /// [`ChannelManager`] having been persisted, another [`Event::PaymentFailed`] may be generated. + /// # Requested Invoices /// - /// [`Event::PaymentFailed`]: events::Event::PaymentFailed - /// [`Event::PaymentSent`]: events::Event::PaymentSent + /// In the case of paying a [`Bolt12Invoice`], abandoning the payment prior to receiving the + /// invoice will result in an [`Event::InvoiceRequestFailed`] and prevent any attempts at paying + /// it once received. The other events may only be generated once the invoice has been received. + /// + /// # Restart Behavior + /// + /// If an [`Event::PaymentFailed`] is generated and we restart without first persisting the + /// [`ChannelManager`], another [`Event::PaymentFailed`] may be generated; likewise for + /// [`Event::InvoiceRequestFailed`]. + /// + /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn abandon_payment(&self, payment_id: PaymentId) { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); self.pending_outbound_payments.abandon_payment(payment_id, PaymentFailureReason::UserAbandoned, &self.pending_events); @@ -3556,11 +3579,13 @@ where pub fn funding_transaction_generated(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); - for inp in funding_transaction.input.iter() { - if inp.witness.is_empty() { - return Err(APIError::APIMisuseError { - err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned() - }); + if !funding_transaction.is_coin_base() { + for inp in funding_transaction.input.iter() { + if inp.witness.is_empty() { + return Err(APIError::APIMisuseError { + err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned() + }); + } } } { @@ -4648,7 +4673,7 @@ where let _ = handle_error!(self, err, counterparty_node_id); } - self.pending_outbound_payments.remove_stale_resolved_payments(&self.pending_events); + self.pending_outbound_payments.remove_stale_payments(&self.pending_events); // Technically we don't need to do this here, but if we have holding cell entries in a // channel that need freeing, it's better to do that here and block a background task @@ -8340,6 +8365,7 @@ where session_priv.write(writer)?; } } + PendingOutboundPayment::AwaitingInvoice { .. } => {}, PendingOutboundPayment::Fulfilled { .. } => {}, PendingOutboundPayment::Abandoned { .. } => {}, } @@ -9648,10 +9674,9 @@ mod tests { let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &expected_route, 100_000); // Next, attempt a keysend payment and make sure it fails. - let route_params = RouteParameters { - payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV, false), - final_value_msat: 100_000, - }; + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), + TEST_FINAL_CLTV, false), 100_000); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph, None, nodes[0].logger, &scorer, &(), &random_seed_bytes @@ -9739,10 +9764,10 @@ mod tests { pass_along_path(&nodes[0], &path, 100_000, payment_hash, None, event, true, Some(payment_preimage)); // Next, attempt a keysend payment and make sure it fails. - let route_params = RouteParameters { - payment_params: PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV, false), - final_value_msat: 100_000, - }; + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::for_keysend(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV, false), + 100_000 + ); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, &nodes[0].network_graph, None, nodes[0].logger, &scorer, &(), &random_seed_bytes @@ -9788,10 +9813,8 @@ mod tests { let payee_pubkey = nodes[1].node.get_our_node_id(); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]); - let route_params = RouteParameters { - payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false), - final_value_msat: 10_000, - }; + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::for_keysend(payee_pubkey, 40, false), 10_000); let network_graph = nodes[0].network_graph.clone(); let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::new(); @@ -9835,10 +9858,8 @@ mod tests { let payee_pubkey = nodes[1].node.get_our_node_id(); let _chan = create_chan_between_nodes(&nodes[0], &nodes[1]); - let route_params = RouteParameters { - payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false), - final_value_msat: 10_000, - }; + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::for_keysend(payee_pubkey, 40, false), 10_000); let network_graph = nodes[0].network_graph.clone(); let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::new(); @@ -10583,7 +10604,7 @@ pub mod bench { use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::{Block, BlockHeader, PackedLockTime, Transaction, TxMerkleNode, TxOut}; - use crate::sync::{Arc, Mutex}; + use crate::sync::{Arc, Mutex, RwLock}; use criterion::Criterion; @@ -10620,7 +10641,7 @@ pub mod bench { let tx_broadcaster = test_utils::TestBroadcaster::new(network); let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }; let logger_a = test_utils::TestLogger::with_id("node a".to_owned()); - let scorer = Mutex::new(test_utils::TestScorer::new()); + let scorer = RwLock::new(test_utils::TestScorer::new()); let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &scorer); let mut config: UserConfig = Default::default(); @@ -10735,9 +10756,9 @@ pub mod bench { let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap(); $node_a.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret), - PaymentId(payment_hash.0), RouteParameters { - payment_params, final_value_msat: 10_000, - }, Retry::Attempts(0)).unwrap(); + PaymentId(payment_hash.0), + RouteParameters::from_payment_params_and_value(payment_params, 10_000), + Retry::Attempts(0)).unwrap(); let payment_event = SendEvent::from_event($node_a.get_and_clear_pending_msg_events().pop().unwrap()); $node_b.handle_update_add_htlc(&$node_a.get_our_node_id(), &payment_event.msgs[0]); $node_b.handle_commitment_signed(&$node_a.get_our_node_id(), &payment_event.commitment_msg);