X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=5b5b85654e833b9f4b01da871caa24a07d8196aa;hb=806b7f0e312c59c87fd628fb71e7c4a77a39645a;hp=d9ce1940c64c7ff6bf5526b4a72fcf89d90b232c;hpb=e74f24332f76beb21d20f9989244db1c57956d3b;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d9ce1940..5b5b8565 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -42,7 +42,8 @@ use crate::events; use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason}; // Since this struct is returned in `list_channels` methods, expose it here in case users want to // construct one themselves. -use crate::ln::{inbound_payment, ChannelId, PaymentHash, PaymentPreimage, PaymentSecret}; +use crate::ln::inbound_payment; +use crate::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channel::{self, Channel, ChannelPhase, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext}; pub use crate::ln::channel::{InboundHTLCDetails, InboundHTLCStateDetails, OutboundHTLCDetails, OutboundHTLCStateDetails}; use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; @@ -357,11 +358,6 @@ enum OnionPayload { /// This is only here for backwards-compatibility in serialization, in the future it can be /// removed, breaking clients running 0.0.106 and earlier. _legacy_hop_data: Option, - /// The context of the payment included by the recipient in a blinded path, or `None` if a - /// blinded path was not used. - /// - /// Used in part to determine the [`events::PaymentPurpose`]. - payment_context: Option, }, /// Contains the payer-provided preimage. Spontaneous(PaymentPreimage), @@ -927,9 +923,9 @@ impl PeerState where SP::Target: SignerProvider { match phase { ChannelPhase::Funded(_) | ChannelPhase::UnfundedOutboundV1(_) => true, ChannelPhase::UnfundedInboundV1(_) => false, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(_) => true, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(_) => false, } ) @@ -1392,7 +1388,7 @@ where /// /// ``` /// # use bitcoin::secp256k1::PublicKey; -/// # use lightning::ln::ChannelId; +/// # use lightning::ln::types::ChannelId; /// # use lightning::ln::channelmanager::AChannelManager; /// # use lightning::events::{Event, EventsProvider}; /// # @@ -1477,6 +1473,8 @@ where /// println!("Claiming spontaneous payment {}", payment_hash); /// channel_manager.claim_funds(payment_preimage); /// }, +/// // ... +/// # _ => {}, /// }, /// Event::PaymentClaimed { payment_hash, amount_msat, .. } => { /// assert_eq!(payment_hash, known_payment_hash); @@ -1493,7 +1491,7 @@ where /// /// ``` /// # use lightning::events::{Event, EventsProvider}; -/// # use lightning::ln::PaymentHash; +/// # use lightning::ln::types::PaymentHash; /// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry}; /// # use lightning::routing::router::RouteParameters; /// # @@ -1552,11 +1550,12 @@ where /// # fn example(channel_manager: T) -> Result<(), Bolt12SemanticError> { /// # let channel_manager = channel_manager.get_cm(); /// let offer = channel_manager -/// .create_offer_builder("coffee".to_string())? +/// .create_offer_builder()? /// # ; /// # // Needed for compiling for c_bindings /// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into(); /// # let offer = builder +/// .description("coffee".to_string()) /// .amount_msats(10_000_000) /// .build()?; /// let bech32_offer = offer.to_string(); @@ -1564,11 +1563,11 @@ where /// // On the event processing thread /// channel_manager.process_pending_events(&|event| match event { /// Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose { -/// PaymentPurpose::Bolt11InvoicePayment { payment_preimage: Some(payment_preimage), .. } => { +/// PaymentPurpose::Bolt12OfferPayment { payment_preimage: Some(payment_preimage), .. } => { /// println!("Claiming payment {}", payment_hash); /// channel_manager.claim_funds(payment_preimage); /// }, -/// PaymentPurpose::Bolt11InvoicePayment { payment_preimage: None, .. } => { +/// PaymentPurpose::Bolt12OfferPayment { payment_preimage: None, .. } => { /// println!("Unknown payment hash: {}", payment_hash); /// }, /// // ... @@ -1655,13 +1654,13 @@ where /// let payment_id = PaymentId([42; 32]); /// let refund = channel_manager /// .create_refund_builder( -/// "coffee".to_string(), amount_msats, absolute_expiry, payment_id, retry, -/// max_total_routing_fee_msat +/// amount_msats, absolute_expiry, payment_id, retry, max_total_routing_fee_msat /// )? /// # ; /// # // Needed for compiling for c_bindings /// # let builder: lightning::offers::refund::RefundBuilder<_> = refund.into(); /// # let refund = builder +/// .description("coffee".to_string()) /// .payer_note("refund for order 1234".to_string()) /// .build()?; /// let bech32_refund = refund.to_string(); @@ -1716,12 +1715,12 @@ where /// // On the event processing thread /// channel_manager.process_pending_events(&|event| match event { /// Event::PaymentClaimable { payment_hash, purpose, .. } => match purpose { -/// PaymentPurpose::Bolt11InvoicePayment { payment_preimage: Some(payment_preimage), .. } => { +/// PaymentPurpose::Bolt12RefundPayment { payment_preimage: Some(payment_preimage), .. } => { /// assert_eq!(payment_hash, known_payment_hash); /// println!("Claiming payment {}", payment_hash); /// channel_manager.claim_funds(payment_preimage); /// }, -/// PaymentPurpose::Bolt11InvoicePayment { payment_preimage: None, .. } => { +/// PaymentPurpose::Bolt12RefundPayment { payment_preimage: None, .. } => { /// println!("Unknown payment hash: {}", payment_hash); /// }, /// // ... @@ -2789,11 +2788,11 @@ macro_rules! convert_chan_phase_err { ChannelPhase::UnfundedInboundV1(channel) => { convert_chan_phase_err!($self, $err, channel, $channel_id, UNFUNDED_CHANNEL) }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(channel) => { convert_chan_phase_err!($self, $err, channel, $channel_id, UNFUNDED_CHANNEL) }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(channel) => { convert_chan_phase_err!($self, $err, channel, $channel_id, UNFUNDED_CHANNEL) }, @@ -3668,8 +3667,8 @@ where // Unfunded channel has no update (None, chan_phase.context().get_counterparty_node_id()) }, - // TODO(dual_funding): Combine this match arm with above once #[cfg(dual_funding)] is removed. - #[cfg(dual_funding)] + // TODO(dual_funding): Combine this match arm with above once #[cfg(any(dual_funding, splicing))] is removed. + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(_) | ChannelPhase::UnfundedInboundV2(_) => { self.finish_close_channel(chan_phase.context_mut().force_shutdown(false, closure_reason)); // Unfunded channel has no update @@ -4483,7 +4482,7 @@ where /// Handles the generation of a funding transaction, optionally (for tests) with a function /// which checks the correctness of the funding transaction given the associated channel. - fn funding_transaction_generated_intern, &Transaction) -> Result>( + fn funding_transaction_generated_intern, &Transaction) -> Result>( &self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction, is_batch_funding: bool, mut find_funding_output: FundingOutput, ) -> Result<(), APIError> { @@ -4496,26 +4495,38 @@ where let funding_txo; let (mut chan, msg_opt) = match peer_state.channel_by_id.remove(temporary_channel_id) { Some(ChannelPhase::UnfundedOutboundV1(mut chan)) => { - funding_txo = find_funding_output(&chan, &funding_transaction)?; + macro_rules! close_chan { ($err: expr, $api_err: expr, $chan: expr) => { { + let counterparty; + let err = if let ChannelError::Close(msg) = $err { + let channel_id = $chan.context.channel_id(); + counterparty = chan.context.get_counterparty_node_id(); + let reason = ClosureReason::ProcessingError { err: msg.clone() }; + let shutdown_res = $chan.context.force_shutdown(false, reason); + MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, shutdown_res, None) + } else { unreachable!(); }; + + mem::drop(peer_state_lock); + mem::drop(per_peer_state); + let _: Result<(), _> = handle_error!(self, Err(err), counterparty); + Err($api_err) + } } } + match find_funding_output(&chan, &funding_transaction) { + Ok(found_funding_txo) => funding_txo = found_funding_txo, + Err(err) => { + let chan_err = ChannelError::Close(err.to_owned()); + let api_err = APIError::APIMisuseError { err: err.to_owned() }; + return close_chan!(chan_err, api_err, chan); + }, + } let logger = WithChannelContext::from(&self.logger, &chan.context); - let funding_res = chan.get_funding_created(funding_transaction, funding_txo, is_batch_funding, &&logger) - .map_err(|(mut chan, e)| if let ChannelError::Close(msg) = e { - let channel_id = chan.context.channel_id(); - let reason = ClosureReason::ProcessingError { err: msg.clone() }; - let shutdown_res = chan.context.force_shutdown(false, reason); - (chan, MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, shutdown_res, None)) - } else { unreachable!(); }); + let funding_res = chan.get_funding_created(funding_transaction, funding_txo, is_batch_funding, &&logger); match funding_res { Ok(funding_msg) => (chan, funding_msg), - Err((chan, err)) => { - mem::drop(peer_state_lock); - mem::drop(per_peer_state); - let _: Result<(), _> = handle_error!(self, Err(err), chan.context.get_counterparty_node_id()); - return Err(APIError::ChannelUnavailable { - err: "Signer refused to sign the initial commitment transaction".to_owned() - }); - }, + Err((mut chan, chan_err)) => { + let api_err = APIError::ChannelUnavailable { err: "Signer refused to sign the initial commitment transaction".to_owned() }; + return close_chan!(chan_err, api_err, chan); + } } }, Some(phase) => { @@ -4680,17 +4691,13 @@ where for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == expected_spk && outp.value == chan.context.get_value_satoshis() { if output_index.is_some() { - return Err(APIError::APIMisuseError { - err: "Multiple outputs matched the expected script and value".to_owned() - }); + return Err("Multiple outputs matched the expected script and value"); } output_index = Some(idx as u16); } } if output_index.is_none() { - return Err(APIError::APIMisuseError { - err: "No output matched the script_pubkey and value in the FundingGenerationReady event".to_owned() - }); + return Err("No output matched the script_pubkey and value in the FundingGenerationReady event"); } let outpoint = OutPoint { txid: tx.txid(), index: output_index.unwrap() }; if let Some(funding_batch_state) = funding_batch_state.as_mut() { @@ -4721,11 +4728,20 @@ where for (channel_id, counterparty_node_id) in channels_to_remove { per_peer_state.get(&counterparty_node_id) .map(|peer_state_mutex| peer_state_mutex.lock().unwrap()) - .and_then(|mut peer_state| peer_state.channel_by_id.remove(&channel_id)) - .map(|mut chan| { + .and_then(|mut peer_state| peer_state.channel_by_id.remove(&channel_id).map(|chan| (chan, peer_state))) + .map(|(mut chan, mut peer_state)| { update_maps_on_chan_removal!(self, &chan.context()); let closure_reason = ClosureReason::ProcessingError { err: e.clone() }; shutdown_results.push(chan.context_mut().force_shutdown(false, closure_reason)); + peer_state.pending_msg_events.push(events::MessageSendEvent::HandleError { + node_id: counterparty_node_id, + action: msgs::ErrorAction::SendErrorMessage { + msg: msgs::ErrorMessage { + channel_id, + data: "Failed to fund channel".to_owned(), + } + }, + }); }); } } @@ -5344,7 +5360,7 @@ where } }) => { let blinded_failure = routing.blinded_failure(); - let (cltv_expiry, onion_payload, payment_data, phantom_shared_secret, mut onion_fields) = match routing { + let (cltv_expiry, onion_payload, payment_data, payment_context, phantom_shared_secret, mut onion_fields) = match routing { PendingHTLCRouting::Receive { payment_data, payment_metadata, payment_context, incoming_cltv_expiry, phantom_shared_secret, custom_tlvs, @@ -5353,8 +5369,8 @@ where let _legacy_hop_data = Some(payment_data.clone()); let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret), payment_metadata, custom_tlvs }; - (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data, payment_context }, - Some(payment_data), phantom_shared_secret, onion_fields) + (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data }, + Some(payment_data), payment_context, phantom_shared_secret, onion_fields) }, PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, @@ -5366,7 +5382,7 @@ where custom_tlvs, }; (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), - payment_data, None, onion_fields) + payment_data, None, None, onion_fields) }, _ => { panic!("short_channel_id == 0 should imply any pending_forward entries are of type Receive"); @@ -5431,10 +5447,7 @@ where macro_rules! check_total_value { ($purpose: expr) => {{ let mut payment_claimable_generated = false; - let is_keysend = match $purpose { - events::PaymentPurpose::SpontaneousPayment(_) => true, - events::PaymentPurpose::Bolt11InvoicePayment { .. } => false, - }; + let is_keysend = $purpose.is_keysend(); let mut claimable_payments = self.claimable_payments.lock().unwrap(); if claimable_payments.pending_claiming_payments.contains_key(&payment_hash) { fail_htlc!(claimable_htlc, payment_hash); @@ -5548,10 +5561,11 @@ where fail_htlc!(claimable_htlc, payment_hash); } } - let purpose = events::PaymentPurpose::Bolt11InvoicePayment { - payment_preimage: payment_preimage.clone(), - payment_secret: payment_data.payment_secret, - }; + let purpose = events::PaymentPurpose::from_parts( + payment_preimage, + payment_data.payment_secret, + payment_context, + ); check_total_value!(purpose); }, OnionPayload::Spontaneous(preimage) => { @@ -5574,10 +5588,11 @@ where &payment_hash, payment_data.total_msat, inbound_payment.get().min_value_msat.unwrap()); fail_htlc!(claimable_htlc, payment_hash); } else { - let purpose = events::PaymentPurpose::Bolt11InvoicePayment { - payment_preimage: inbound_payment.get().payment_preimage, - payment_secret: payment_data.payment_secret, - }; + let purpose = events::PaymentPurpose::from_parts( + inbound_payment.get().payment_preimage, + payment_data.payment_secret, + payment_context, + ); let payment_claimable_generated = check_total_value!(purpose); if payment_claimable_generated { inbound_payment.remove_entry(); @@ -5898,12 +5913,12 @@ where process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context, pending_msg_events, counterparty_node_id) }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(chan) => { process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context, pending_msg_events, counterparty_node_id) }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(chan) => { process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context, pending_msg_events, counterparty_node_id) @@ -7075,8 +7090,8 @@ where num_unfunded_channels += 1; } }, - // TODO(dual_funding): Combine this match arm with above once #[cfg(dual_funding)] is removed. - #[cfg(dual_funding)] + // TODO(dual_funding): Combine this match arm with above once #[cfg(any(dual_funding, splicing))] is removed. + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(chan) => { // Only inbound V2 channels that are not 0conf and that we do not contribute to will be // included in the unfunded count. @@ -7089,8 +7104,8 @@ where // Outbound channels don't contribute to the unfunded count in the DoS context. continue; }, - // TODO(dual_funding): Combine this match arm with above once #[cfg(dual_funding)] is removed. - #[cfg(dual_funding)] + // TODO(dual_funding): Combine this match arm with above once #[cfg(any(dual_funding, splicing))] is removed. + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(_) => { // Outbound channels don't contribute to the unfunded count in the DoS context. continue; @@ -7517,7 +7532,7 @@ where finish_shutdown = Some(chan.context_mut().force_shutdown(false, ClosureReason::CounterpartyCoopClosedUnfundedChannel)); }, // TODO(dual_funding): Combine this match arm with above. - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(_) | ChannelPhase::UnfundedOutboundV2(_) => { let context = phase.context_mut(); log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", &msg.channel_id); @@ -7669,7 +7684,7 @@ where } } } - try_chan_phase_entry!(self, chan.update_add_htlc(&msg, pending_forward_info), chan_phase_entry); + try_chan_phase_entry!(self, chan.update_add_htlc(&msg, pending_forward_info, &self.fee_estimator), chan_phase_entry); } else { return try_chan_phase_entry!(self, Err(ChannelError::Close( "Got an update_add_htlc message for an unfunded channel!".into())), chan_phase_entry); @@ -8549,9 +8564,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { /// /// [`Offer`]: crate::offers::offer::Offer /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest - pub fn create_offer_builder( - &$self, description: String - ) -> Result<$builder, Bolt12SemanticError> { + pub fn create_offer_builder(&$self) -> Result<$builder, Bolt12SemanticError> { let node_id = $self.get_our_node_id(); let expanded_key = &$self.inbound_payment_key; let entropy = &*$self.entropy_source; @@ -8559,7 +8572,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?; let builder = OfferBuilder::deriving_signing_pubkey( - description, node_id, expanded_key, entropy, secp_ctx + node_id, expanded_key, entropy, secp_ctx ) .chain_hash($self.chain_hash) .path(path); @@ -8618,8 +8631,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => { /// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths /// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments pub fn create_refund_builder( - &$self, description: String, amount_msats: u64, absolute_expiry: Duration, - payment_id: PaymentId, retry_strategy: Retry, max_total_routing_fee_msat: Option + &$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId, + retry_strategy: Retry, max_total_routing_fee_msat: Option ) -> Result<$builder, Bolt12SemanticError> { let node_id = $self.get_our_node_id(); let expanded_key = &$self.inbound_payment_key; @@ -8628,7 +8641,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => { let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?; let builder = RefundBuilder::deriving_payer_id( - description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id + node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id )? .chain_hash($self.chain_hash) .absolute_expiry(absolute_expiry) @@ -8761,14 +8774,7 @@ where .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?; let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap(); - if offer.paths().is_empty() { - let message = new_pending_onion_message( - OffersMessage::InvoiceRequest(invoice_request), - Destination::Node(offer.signing_pubkey()), - Some(reply_path), - ); - pending_offers_messages.push(message); - } else { + if !offer.paths().is_empty() { // Send as many invoice requests as there are paths in the offer (with an upper bound). // Using only one path could result in a failure if the path no longer exists. But only // one invoice for a given payment id will be paid, even if more than one is received. @@ -8781,6 +8787,16 @@ where ); pending_offers_messages.push(message); } + } else if let Some(signing_pubkey) = offer.signing_pubkey() { + let message = new_pending_onion_message( + OffersMessage::InvoiceRequest(invoice_request), + Destination::Node(signing_pubkey), + Some(reply_path), + ); + pending_offers_messages.push(message); + } else { + debug_assert!(false); + return Err(Bolt12SemanticError::MissingSigningPubkey); } Ok(()) @@ -8880,10 +8896,9 @@ where /// This differs from [`create_inbound_payment_for_hash`] only in that it generates the /// [`PaymentHash`] and [`PaymentPreimage`] for you. /// - /// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentClaimable`], which - /// will have the [`PaymentClaimable::purpose`] be [`PaymentPurpose::Bolt11InvoicePayment`] with - /// its [`PaymentPurpose::Bolt11InvoicePayment::payment_preimage`] field filled in. That should - /// then be passed directly to [`claim_funds`]. + /// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentClaimable`] event, which + /// will have the [`PaymentClaimable::purpose`] return `Some` for [`PaymentPurpose::preimage`]. That + /// should then be passed directly to [`claim_funds`]. /// /// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements. /// @@ -8903,8 +8918,7 @@ where /// [`claim_funds`]: Self::claim_funds /// [`PaymentClaimable`]: events::Event::PaymentClaimable /// [`PaymentClaimable::purpose`]: events::Event::PaymentClaimable::purpose - /// [`PaymentPurpose::Bolt11InvoicePayment`]: events::PaymentPurpose::Bolt11InvoicePayment - /// [`PaymentPurpose::Bolt11InvoicePayment::payment_preimage`]: events::PaymentPurpose::Bolt11InvoicePayment::payment_preimage + /// [`PaymentPurpose::preimage`]: events::PaymentPurpose::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, min_final_cltv_expiry_delta: Option) -> Result<(PaymentHash, PaymentSecret), ()> { @@ -9472,7 +9486,7 @@ where // Retain unfunded channels. ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => true, // TODO(dual_funding): Combine this match arm with above. - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(_) | ChannelPhase::UnfundedInboundV2(_) => true, ChannelPhase::Funded(channel) => { let res = f(channel); @@ -9778,18 +9792,21 @@ where msg.channel_id.clone())), *counterparty_node_id); } + #[cfg(splicing)] fn handle_splice(&self, counterparty_node_id: &PublicKey, msg: &msgs::Splice) { let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( "Splicing not supported".to_owned(), msg.channel_id.clone())), *counterparty_node_id); } + #[cfg(splicing)] fn handle_splice_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceAck) { let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( "Splicing not supported (splice_ack)".to_owned(), msg.channel_id.clone())), *counterparty_node_id); } + #[cfg(splicing)] fn handle_splice_locked(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceLocked) { let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( "Splicing not supported (splice_locked)".to_owned(), @@ -9947,11 +9964,11 @@ where ChannelPhase::UnfundedInboundV1(chan) => { &mut chan.context }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(chan) => { &mut chan.context }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(chan) => { &mut chan.context }, @@ -10112,8 +10129,8 @@ where }); } - // TODO(dual_funding): Combine this match arm with above once #[cfg(dual_funding)] is removed. - #[cfg(dual_funding)] + // TODO(dual_funding): Combine this match arm with above once #[cfg(any(dual_funding, splicing))] is removed. + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedOutboundV2(chan) => { pending_msg_events.push(events::MessageSendEvent::SendOpenChannelV2 { node_id: chan.context.get_counterparty_node_id(), @@ -10128,8 +10145,8 @@ where debug_assert!(false); } - // TODO(dual_funding): Combine this match arm with above once #[cfg(dual_funding)] is removed. - #[cfg(dual_funding)] + // TODO(dual_funding): Combine this match arm with above once #[cfg(any(dual_funding, splicing))] is removed. + #[cfg(any(dual_funding, splicing))] ChannelPhase::UnfundedInboundV2(channel) => { // Since unfunded inbound channel maps are cleared upon disconnecting a peer, // they are not persisted and won't be recovered after a crash. @@ -10232,7 +10249,7 @@ where return; } }, - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] Some(ChannelPhase::UnfundedOutboundV2(ref mut chan)) => { if let Ok(msg) = chan.maybe_handle_error_without_close(self.chain_hash, &self.fee_estimator) { peer_state.pending_msg_events.push(events::MessageSendEvent::SendOpenChannelV2 { @@ -10243,7 +10260,7 @@ where } }, None | Some(ChannelPhase::UnfundedInboundV1(_) | ChannelPhase::Funded(_)) => (), - #[cfg(dual_funding)] + #[cfg(any(dual_funding, splicing))] Some(ChannelPhase::UnfundedInboundV2(_)) => (), } } @@ -10365,6 +10382,7 @@ where let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext { offer_id: invoice_request.offer_id, + invoice_request: invoice_request.fields(), }); let payment_paths = match self.create_blinded_payment_paths( amount_msats, payment_secret, payment_context @@ -10809,11 +10827,11 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, { impl Writeable for ClaimableHTLC { fn write(&self, writer: &mut W) -> Result<(), io::Error> { - let (payment_data, keysend_preimage, payment_context) = match &self.onion_payload { - OnionPayload::Invoice { _legacy_hop_data, payment_context } => { - (_legacy_hop_data.as_ref(), None, payment_context.as_ref()) + let (payment_data, keysend_preimage) = match &self.onion_payload { + OnionPayload::Invoice { _legacy_hop_data } => { + (_legacy_hop_data.as_ref(), None) }, - OnionPayload::Spontaneous(preimage) => (None, Some(preimage), None), + OnionPayload::Spontaneous(preimage) => (None, Some(preimage)), }; write_tlv_fields!(writer, { (0, self.prev_hop, required), @@ -10825,7 +10843,6 @@ impl Writeable for ClaimableHTLC { (6, self.cltv_expiry, required), (8, keysend_preimage, option), (10, self.counterparty_skimmed_fee_msat, option), - (11, payment_context, option), }); Ok(()) } @@ -10843,7 +10860,6 @@ impl Readable for ClaimableHTLC { (6, cltv_expiry, required), (8, keysend_preimage, option), (10, counterparty_skimmed_fee_msat, option), - (11, payment_context, option), }); let payment_data: Option = payment_data_opt; let value = value_ser.0.unwrap(); @@ -10864,7 +10880,7 @@ impl Readable for ClaimableHTLC { } total_msat = Some(payment_data.as_ref().unwrap().total_msat); } - OnionPayload::Invoice { _legacy_hop_data: payment_data, payment_context } + OnionPayload::Invoice { _legacy_hop_data: payment_data } }, }; Ok(Self { @@ -11059,9 +11075,10 @@ where best_block.block_hash.write(writer)?; } + let per_peer_state = self.per_peer_state.write().unwrap(); + let mut serializable_peer_count: u64 = 0; { - let per_peer_state = self.per_peer_state.read().unwrap(); let mut number_of_funded_channels = 0; for (_, peer_state_mutex) in per_peer_state.iter() { let mut peer_state_lock = peer_state_mutex.lock().unwrap(); @@ -11108,8 +11125,6 @@ where decode_update_add_htlcs_opt = Some(decode_update_add_htlcs); } - let per_peer_state = self.per_peer_state.write().unwrap(); - let pending_inbound_payments = self.pending_inbound_payments.lock().unwrap(); let claimable_payments = self.claimable_payments.lock().unwrap(); let pending_outbound_payments = self.pending_outbound_payments.pending_outbound_payments.lock().unwrap(); @@ -11556,9 +11571,10 @@ where } } } else { - log_info!(logger, "Successfully loaded channel {} at update_id {} against monitor at update id {}", + channel.on_startup_drop_completed_blocked_mon_updates_through(&logger, monitor.get_latest_update_id()); + log_info!(logger, "Successfully loaded channel {} at update_id {} against monitor at update id {} with {} blocked updates", &channel.context.channel_id(), channel.context.get_latest_monitor_update_id(), - monitor.get_latest_update_id()); + monitor.get_latest_update_id(), channel.blocked_monitor_updates_pending()); if let Some(short_channel_id) = channel.context.get_short_channel_id() { short_to_chan_info.insert(short_channel_id, (channel.context.get_counterparty_node_id(), channel.context.channel_id())); } @@ -11883,6 +11899,7 @@ where log_error!(logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!"); log_error!(logger, " Without the latest ChannelMonitor we cannot continue without risking funds."); log_error!(logger, " Please ensure the chain::Watch API requirements are met and file a bug report at https://github.com/lightningdevkit/rust-lightning"); + log_error!(logger, " Pending in-flight updates are: {:?}", chan_in_flight_updates); return Err(DecodeError::InvalidValue); } } @@ -12101,7 +12118,7 @@ where return Err(DecodeError::InvalidValue); } let purpose = match &htlcs[0].onion_payload { - OnionPayload::Invoice { _legacy_hop_data, payment_context: _ } => { + OnionPayload::Invoice { _legacy_hop_data } => { if let Some(hop_data) = _legacy_hop_data { events::PaymentPurpose::Bolt11InvoicePayment { payment_preimage: match pending_inbound_payments.get(&payment_hash) { @@ -12358,8 +12375,7 @@ mod tests { use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use core::sync::atomic::Ordering; use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; - use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; - use crate::ln::ChannelId; + use crate::ln::types::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; use crate::ln::channelmanager::{create_recv_pending_htlc_info, HTLCForwardInfo, inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId}; use crate::ln::functional_test_utils::*; use crate::ln::msgs::{self, ErrorAction};