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};
/// 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<msgs::FinalOnionHopData>,
- /// 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<PaymentContext>,
},
/// Contains the payer-provided preimage.
Spontaneous(PaymentPreimage),
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,
}
)
///
/// ```
/// # use bitcoin::secp256k1::PublicKey;
-/// # use lightning::ln::ChannelId;
+/// # use lightning::ln::types::ChannelId;
/// # use lightning::ln::channelmanager::AChannelManager;
/// # use lightning::events::{Event, EventsProvider};
/// #
///
/// ```
/// # 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;
/// #
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)
},
// 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
}
}) => {
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,
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,
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");
match payment_secrets.entry(payment_hash) {
hash_map::Entry::Vacant(_) => {
match claimable_htlc.onion_payload {
- OnionPayload::Invoice { ref payment_context, .. } => {
+ OnionPayload::Invoice { .. } => {
let payment_data = payment_data.unwrap();
let (payment_preimage, min_final_cltv_expiry_delta) = match inbound_payment::verify(payment_hash, &payment_data, self.highest_seen_timestamp.load(Ordering::Acquire) as u64, &self.inbound_payment_key, &self.logger) {
Ok(result) => result,
}
}
let purpose = events::PaymentPurpose::from_parts(
- payment_preimage.clone(),
+ payment_preimage,
payment_data.payment_secret,
- payment_context.clone(),
+ payment_context,
);
check_total_value!(purpose);
},
}
},
hash_map::Entry::Occupied(inbound_payment) => {
- let payment_context = match claimable_htlc.onion_payload {
- OnionPayload::Spontaneous(_) => {
- log_trace!(self.logger, "Failing new keysend HTLC with payment_hash {} because we already have an inbound payment with the same payment hash", &payment_hash);
- fail_htlc!(claimable_htlc, payment_hash);
- },
- OnionPayload::Invoice { ref payment_context, .. } => payment_context,
- };
+ if let OnionPayload::Spontaneous(_) = claimable_htlc.onion_payload {
+ log_trace!(self.logger, "Failing new keysend HTLC with payment_hash {} because we already have an inbound payment with the same payment hash", &payment_hash);
+ fail_htlc!(claimable_htlc, payment_hash);
+ }
let payment_data = payment_data.unwrap();
if inbound_payment.get().payment_secret != payment_data.payment_secret {
log_trace!(self.logger, "Failing new HTLC with payment_hash {} as it didn't match our expected payment secret.", &payment_hash);
let purpose = events::PaymentPurpose::from_parts(
inbound_payment.get().payment_preimage,
payment_data.payment_secret,
- payment_context.clone(),
+ payment_context,
);
let payment_claimable_generated = check_total_value!(purpose);
if payment_claimable_generated {
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)
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.
// 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;
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);
.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.
);
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(())
// 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);
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(),
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
},
});
}
- // 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(),
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.
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 {
}
},
None | Some(ChannelPhase::UnfundedInboundV1(_) | ChannelPhase::Funded(_)) => (),
- #[cfg(dual_funding)]
+ #[cfg(any(dual_funding, splicing))]
Some(ChannelPhase::UnfundedInboundV2(_)) => (),
}
}
impl Writeable for ClaimableHTLC {
fn write<W: Writer>(&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),
(6, self.cltv_expiry, required),
(8, keysend_preimage, option),
(10, self.counterparty_skimmed_fee_msat, option),
- (11, payment_context, option),
});
Ok(())
}
(6, cltv_expiry, required),
(8, keysend_preimage, option),
(10, counterparty_skimmed_fee_msat, option),
- (11, payment_context, option),
});
let payment_data: Option<msgs::FinalOnionHopData> = payment_data_opt;
let value = value_ser.0.unwrap();
}
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 {
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();
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();
}
}
} 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()));
}
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);
}
}
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) {
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};