diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 4f3b55804c7..06d63d2e0a2 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -21,6 +21,7 @@ pub mod bump_transaction; pub use bump_transaction::BumpTransactionEvent; use crate::chain::keysinterface::SpendableOutputDescriptor; +use crate::chain::transaction::OutPoint; use crate::ln::channelmanager::{InterceptId, PaymentId}; use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS; use crate::ln::features::ChannelTypeFeatures; @@ -604,6 +605,50 @@ pub enum Event { /// transaction. claim_from_onchain_tx: bool, }, + /// Indicates a channel has received sufficient confirmations and LDK is ready to send [`msgs::ChannelReady`]. + /// + /// To signal readiness, call [`ChannelManager::signal_channel_readiness`]. To reject the + /// request, call [`ChannelManager::force_close_broadcasting_latest_txn`]. + /// + /// The event is only triggered when the [`ChannelHandshakeConfig::manually_signal_channel_ready`] + /// config flag is set to true. + /// + /// [`ChannelManager::signal_channel_readiness`]: crate::ln::channelmanager::ChannelManager::signal_channel_readiness + /// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn + /// [`ChannelHandshakeConfig::manually_signal_channel_ready`]: crate::util::config::ChannelHandshakeConfig::manually_signal_channel_ready + /// [`msgs::ChannelReady`]: crate::ln::msgs::ChannelReady + PendingChannelReady { + /// The channel ID of the channel. + /// + /// When responding to the request, the `channel_id` should be passed + /// back to the ChannelManager through [`ChannelManager::signal_channel_readiness`] to signal, + /// or through [`ChannelManager::force_close_broadcasting_latest_txn`] to reject. + /// + /// [`ChannelManager::signal_channel_readiness`]: crate::ln::channelmanager::ChannelManager::signal_channel_readiness + /// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn + channel_id: [u8; 32], + /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound + /// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if + /// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise + /// `user_channel_id` will be randomized for an inbound channel. + /// + /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel + /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel + /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels + user_channel_id: u128, + /// The node_id of the counterparty requesting to open the channel. + /// + /// When responding to the request, the `counterparty_node_id` should be passed + /// back to the `ChannelManager` through [`ChannelManager::signal_channel_readiness`] to + /// signal readiness, or through [`ChannelManager::force_close_broadcasting_latest_txn`] to reject the + /// request. + /// + /// [`ChannelManager::signal_channel_readiness`]: crate::ln::channelmanager::ChannelManager::signal_channel_readiness + /// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn + counterparty_node_id: PublicKey, + /// The outpoint that holds the channel funds on-chain. + funding_outpoint: OutPoint, + }, /// Used to indicate that a channel with the given `channel_id` is ready to /// be used. This event is emitted either when the funding transaction has been confirmed /// on-chain, or, in case of a 0conf channel, when both parties have confirmed the channel @@ -923,6 +968,15 @@ impl Writeable for Event { (6, channel_type, required), }); }, + &Event::PendingChannelReady { ref channel_id, ref user_channel_id, ref counterparty_node_id, ref funding_outpoint } => { + 31u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, counterparty_node_id, required), + (6, funding_outpoint, required) + }); + }, // Note that, going forward, all new events must only write data inside of // `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write // data via `write_tlv_fields`. @@ -1258,6 +1312,28 @@ impl MaybeReadable for Event { }; f() }, + 31u8 => { + let f = || { + let mut channel_id = [0; 32]; + let mut user_channel_id: u128 = 0; + let mut counterparty_node_id = RequiredWrapper(None); + let mut funding_outpoint = RequiredWrapper(None); + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, user_channel_id, required), + (4, counterparty_node_id, required), + (6, funding_outpoint, required), + }); + + Ok(Some(Event::PendingChannelReady { + channel_id, + user_channel_id, + counterparty_node_id: counterparty_node_id.0.unwrap(), + funding_outpoint: funding_outpoint.0.unwrap() + })) + }; + f() + }, // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue. // Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt // reads. diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f470469426e..d7e51ec625e 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -52,6 +52,28 @@ use core::ops::Deref; use crate::sync::Mutex; use bitcoin::hashes::hex::ToHex; +pub(crate) enum ChannelReadyStatus { + ReadyToSend(msgs::ChannelReady), + PendingChannelReady, + NotReady +} + +impl ChannelReadyStatus { + pub fn is_ready(&self) -> bool { + match self { + ChannelReadyStatus::ReadyToSend(_) => true, + _ => false, + } + } + + pub fn is_pending_channel_ready(&self) -> bool { + match self { + ChannelReadyStatus::PendingChannelReady => true, + _ => false, + } + } +} + #[cfg(test)] pub struct ChannelValueStat { pub value_to_self_msat: u64, @@ -75,6 +97,24 @@ pub struct AvailableBalances { pub next_outbound_htlc_limit_msat: u64, } +pub(crate) struct ChainActionUpdates { + pub(crate) channel_ready_msg: Option, + pub(crate) timed_out_htlcs: Vec<(HTLCSource, PaymentHash)>, + pub(crate) announcement_sigs: Option, + pub(crate) pending_channel_ready: bool +} + +impl ChainActionUpdates { + pub fn no_updates() -> Self { + ChainActionUpdates { + channel_ready_msg: None, + timed_out_htlcs: Vec::new(), + announcement_sigs: None, + pending_channel_ready: false, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq)] enum FeeUpdateState { // Inbound states mirroring InboundHTLCState @@ -612,6 +652,14 @@ pub(super) struct Channel { /// `accept_inbound_channel`, and `funding_created` should therefore not execute successfully. inbound_awaiting_accept: bool, + /// A flag that indicates whether the channel requires the user to signal readiness to send + /// the `msgs::ChannelReady` message. This is only set to true if the channel was created with a + /// `ChannelHandshakeConfig::manually_signal_channel_ready` flag set to true. + /// + /// When a user signals readiness via `ChannelManager::signal_channel_readiness` this flag is + /// flipped to false. + requires_manual_readiness_signal: bool, + /// The hash of the block in which the funding transaction was included. funding_tx_confirmed_in: Option, funding_tx_confirmation_height: u32, @@ -731,6 +779,8 @@ pub(super) struct Channel { // We track whether we already emitted a `ChannelReady` event. channel_ready_event_emitted: bool, + // We track whether we already emitted a `PendingChannelReady` event. + pending_channel_ready_event_emitted: bool, /// The unique identifier used to re-derive the private key material for the channel through /// [`SignerProvider::derive_channel_signer`]. @@ -1049,6 +1099,7 @@ impl Channel { target_closing_feerate_sats_per_kw: None, inbound_awaiting_accept: false, + requires_manual_readiness_signal: config.channel_handshake_config.manually_signal_channel_ready, funding_tx_confirmed_in: None, funding_tx_confirmation_height: 0, @@ -1104,6 +1155,7 @@ impl Channel { outbound_scid_alias, channel_ready_event_emitted: false, + pending_channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills: HashSet::new(), @@ -1393,6 +1445,7 @@ impl Channel { target_closing_feerate_sats_per_kw: None, inbound_awaiting_accept: true, + requires_manual_readiness_signal: config.channel_handshake_config.manually_signal_channel_ready, funding_tx_confirmed_in: None, funding_tx_confirmation_height: 0, @@ -1452,6 +1505,7 @@ impl Channel { outbound_scid_alias, channel_ready_event_emitted: false, + pending_channel_ready_event_emitted: false, #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills: HashSet::new(), @@ -2347,7 +2401,7 @@ impl Channel { log_info!(logger, "Generated funding_signed for peer for channel {}", log_bytes!(self.channel_id())); - let need_channel_ready = self.check_get_channel_ready(0).is_some(); + let need_channel_ready = self.check_get_channel_ready(0).is_ready(); self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); Ok((msgs::FundingSigned { @@ -2435,7 +2489,7 @@ impl Channel { log_info!(logger, "Received funding_signed from peer for channel {}", log_bytes!(self.channel_id())); - let need_channel_ready = self.check_get_channel_ready(0).is_some(); + let need_channel_ready = self.check_get_channel_ready(0).is_ready(); self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); Ok(channel_monitor) } @@ -4704,6 +4758,20 @@ impl Channel { self.channel_ready_event_emitted = true; } + // Checks whether we should emit a `PendingChannelReady` event. + pub(crate) fn should_emit_pending_channel_ready_event(&self) -> bool { + self.requires_manual_readiness_signal && !self.pending_channel_ready_event_emitted + } + + // Remembers that we already emitted a `PendingChannelReady` event. + pub(crate) fn set_pending_channel_ready_event_emitted(&mut self) { + self.pending_channel_ready_event_emitted = true; + } + + pub(crate) fn unset_requires_manual_readiness_signal(&mut self) { + self.requires_manual_readiness_signal = false; + } + /// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once /// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will /// no longer be considered when forwarding HTLCs. @@ -4968,12 +5036,12 @@ impl Channel { self.channel_update_status = status; } - fn check_get_channel_ready(&mut self, height: u32) -> Option { + pub fn check_get_channel_ready(&mut self, height: u32) -> ChannelReadyStatus { // Called: // * always when a new block/transactions are confirmed with the new height // * when funding is signed with a height of 0 if self.funding_tx_confirmation_height == 0 && self.minimum_depth != Some(0) { - return None; + return ChannelReadyStatus::NotReady; } let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; @@ -4982,7 +5050,11 @@ impl Channel { } if funding_tx_confirmations < self.minimum_depth.unwrap_or(0) as i64 { - return None; + return ChannelReadyStatus::NotReady; + } + + if self.should_emit_pending_channel_ready_event() { + return ChannelReadyStatus::PendingChannelReady; } let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); @@ -5016,7 +5088,7 @@ impl Channel { if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 { let next_per_commitment_point = self.holder_signer.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - 1, &self.secp_ctx); - return Some(msgs::ChannelReady { + return ChannelReadyStatus::ReadyToSend(msgs::ChannelReady { channel_id: self.channel_id, next_per_commitment_point, short_channel_id_alias: Some(self.outbound_scid_alias), @@ -5026,7 +5098,7 @@ impl Channel { self.monitor_pending_channel_ready = true; } } - None + ChannelReadyStatus::NotReady } /// When a transaction is confirmed, we check whether it is or spends the funding transaction @@ -5035,7 +5107,7 @@ impl Channel { pub fn transactions_confirmed( &mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData, genesis_block_hash: BlockHash, node_signer: &NS, user_config: &UserConfig, logger: &L - ) -> Result<(Option, Option), ClosureReason> + ) -> Result where NS::Target: NodeSigner, L::Target: Logger @@ -5083,10 +5155,26 @@ impl Channel { // If we allow 1-conf funding, we may need to check for channel_ready here and // send it immediately instead of waiting for a best_block_updated call (which // may have already happened for this block). - if let Some(channel_ready) = self.check_get_channel_ready(height) { - log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.channel_id)); - let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger); - return Ok((Some(channel_ready), announcement_sigs)); + match self.check_get_channel_ready(height) { + ChannelReadyStatus::ReadyToSend(channel_ready) => { + log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.channel_id)); + let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger); + return Ok(ChainActionUpdates { + channel_ready_msg: Some(channel_ready), + announcement_sigs, + timed_out_htlcs: vec![], + pending_channel_ready: false + }); + }, + ChannelReadyStatus::PendingChannelReady => { + return Ok(ChainActionUpdates { + channel_ready_msg: None, + announcement_sigs: None, + timed_out_htlcs: vec![], + pending_channel_ready: true + }); + }, + ChannelReadyStatus::NotReady => {} } } for inp in tx.input.iter() { @@ -5097,7 +5185,7 @@ impl Channel { } } } - Ok((None, None)) + Ok(ChainActionUpdates::no_updates()) } /// When a new block is connected, we check the height of the block against outbound holding @@ -5114,7 +5202,7 @@ impl Channel { pub fn best_block_updated( &mut self, height: u32, highest_header_time: u32, genesis_block_hash: BlockHash, node_signer: &NS, user_config: &UserConfig, logger: &L - ) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason> + ) -> Result where NS::Target: NodeSigner, L::Target: Logger @@ -5125,7 +5213,7 @@ impl Channel { fn do_best_block_updated( &mut self, height: u32, highest_header_time: u32, genesis_node_signer: Option<(BlockHash, &NS, &UserConfig)>, logger: &L - ) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason> + ) -> Result where NS::Target: NodeSigner, L::Target: Logger @@ -5149,12 +5237,19 @@ impl Channel { self.update_time_counter = cmp::max(self.update_time_counter, highest_header_time); - if let Some(channel_ready) = self.check_get_channel_ready(height) { + let channel_ready_status = self.check_get_channel_ready(height); + + if let ChannelReadyStatus::ReadyToSend(channel_ready) = channel_ready_status { let announcement_sigs = if let Some((genesis_block_hash, node_signer, user_config)) = genesis_node_signer { self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger) } else { None }; log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.channel_id)); - return Ok((Some(channel_ready), timed_out_htlcs, announcement_sigs)); + return Ok(ChainActionUpdates { + channel_ready_msg: Some(channel_ready), + timed_out_htlcs, + announcement_sigs, + pending_channel_ready: false + }); } let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); @@ -5194,7 +5289,12 @@ impl Channel { let announcement_sigs = if let Some((genesis_block_hash, node_signer, user_config)) = genesis_node_signer { self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger) } else { None }; - Ok((None, timed_out_htlcs, announcement_sigs)) + Ok(ChainActionUpdates { + channel_ready_msg: None, + timed_out_htlcs, + announcement_sigs, + pending_channel_ready: channel_ready_status.is_pending_channel_ready() + }) } /// Indicates the funding transaction is no longer confirmed in the main chain. This may @@ -5210,10 +5310,10 @@ impl Channel { // time we saw and it will be ignored. let best_time = self.update_time_counter; match self.do_best_block_updated(reorg_height, best_time, None::<(BlockHash, &&NodeSigner, &UserConfig)>, logger) { - Ok((channel_ready, timed_out_htlcs, announcement_sigs)) => { - assert!(channel_ready.is_none(), "We can't generate a funding with 0 confirmations?"); - assert!(timed_out_htlcs.is_empty(), "We can't have accepted HTLCs with a timeout before our funding confirmation?"); - assert!(announcement_sigs.is_none(), "We can't generate an announcement_sigs with 0 confirmations?"); + Ok(chain_action_updates) => { + assert!(chain_action_updates.channel_ready_msg.is_none(), "We can't generate a funding with 0 confirmations?"); + assert!(chain_action_updates.timed_out_htlcs.is_empty(), "We can't have accepted HTLCs with a timeout before our funding confirmation?"); + assert!(chain_action_updates.announcement_sigs.is_none(), "We can't generate an announcement_sigs with 0 confirmations?"); Ok(()) }, Err(e) => Err(e) @@ -5273,6 +5373,10 @@ impl Channel { self.inbound_awaiting_accept } + pub fn requires_manual_readiness_signal(&self) -> bool { + self.requires_manual_readiness_signal + } + /// Sets this channel to accepting 0conf, must be done before `get_accept_channel` pub fn set_0conf(&mut self) { assert!(self.inbound_awaiting_accept); @@ -6421,12 +6525,15 @@ impl Writeable for Channel { { Some(self.holder_max_htlc_value_in_flight_msat) } else { None }; let channel_ready_event_emitted = Some(self.channel_ready_event_emitted); + let pending_channel_ready_event_emitted = Some(self.pending_channel_ready_event_emitted); // `user_id` used to be a single u64 value. In order to remain backwards compatible with // versions prior to 0.0.113, the u128 is serialized as two separate u64 values. Therefore, // we write the high bytes as an option here. let user_id_high_opt = Some((self.user_id >> 64) as u64); + let requires_manual_readiness_signal = Some(self.requires_manual_readiness_signal); + write_tlv_fields!(writer, { (0, self.announcement_sigs, option), // minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a @@ -6452,6 +6559,8 @@ impl Writeable for Channel { (23, channel_ready_event_emitted, option), (25, user_id_high_opt, option), (27, self.channel_keys_id, required), + (29, requires_manual_readiness_signal, option), + (31, pending_channel_ready_event_emitted, option), }); Ok(()) @@ -6723,6 +6832,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let mut user_id_high_opt: Option = None; let mut channel_keys_id: Option<[u8; 32]> = None; + let mut requires_manual_readiness_signal: Option = Some(false); + let mut pending_channel_ready_event_emitted = None; read_tlv_fields!(reader, { (0, announcement_sigs, option), @@ -6743,6 +6854,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch (23, channel_ready_event_emitted, option), (25, user_id_high_opt, option), (27, channel_keys_id, option), + (29, requires_manual_readiness_signal, option), + (31, pending_channel_ready_event_emitted, option), }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { @@ -6853,6 +6966,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch target_closing_feerate_sats_per_kw, inbound_awaiting_accept: false, + requires_manual_readiness_signal: requires_manual_readiness_signal.unwrap(), funding_tx_confirmed_in, funding_tx_confirmation_height, @@ -6900,6 +7014,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch outbound_scid_alias: outbound_scid_alias.unwrap_or(0), channel_ready_event_emitted: channel_ready_event_emitted.unwrap_or(true), + pending_channel_ready_event_emitted: pending_channel_ready_event_emitted.unwrap_or(true), #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 6bd9148e987..b9c8690b392 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -40,7 +40,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa // 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, PaymentHash, PaymentPreimage, PaymentSecret}; -use crate::ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch}; +use crate::ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch, ChainActionUpdates, ChannelReadyStatus}; use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; #[cfg(any(feature = "_test_utils", test))] use crate::ln::features::InvoiceFeatures; @@ -1504,6 +1504,23 @@ macro_rules! emit_channel_ready_event { } } +macro_rules! emit_pending_channel_ready_event { + ($self: expr, $channel: expr) => { + if $channel.should_emit_channel_ready_event() { + { + let mut pending_events = $self.pending_events.lock().unwrap(); + pending_events.push(events::Event::PendingChannelReady { + channel_id: $channel.channel_id(), + user_channel_id: $channel.get_user_id(), + counterparty_node_id: $channel.get_counterparty_node_id(), + funding_outpoint: $channel.get_funding_txo().unwrap(), + }); + } + $channel.set_pending_channel_ready_event_emitted(); + } + } +} + macro_rules! handle_monitor_update_completion { ($self: ident, $update_id: expr, $peer_state_lock: expr, $peer_state: expr, $per_peer_state_lock: expr, $chan: expr) => { { let mut updates = $chan.monitor_updating_restored(&$self.logger, @@ -4389,6 +4406,41 @@ where Ok(()) } + /// Signals channel readiness after a [`Event::PendingChannelReady`]. + /// + /// The `channel_id` parameter indicates which channel should signal readiness, + /// and the `counterparty_node_id` parameter is the id of the peer the channel is with. + /// + /// [`Event::PendingChannelReady`]: events::Event::PendingChannelReady + pub fn signal_channel_readiness(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey) -> Result<(), APIError> { + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); + + let per_peer_state = self.per_peer_state.read().unwrap(); + let peer_state_mutex = per_peer_state.get(counterparty_node_id) + .ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id) })?; + let mut peer_state_lock = peer_state_mutex.lock().unwrap(); + let peer_state = &mut *peer_state_lock; + let pending_msg_events = &mut peer_state.pending_msg_events; + match peer_state.channel_by_id.entry(channel_id.clone()) { + hash_map::Entry::Occupied(mut channel) => { + let best_block_height = self.best_block.read().unwrap().height(); + let channel = channel.get_mut(); + match channel.check_get_channel_ready(best_block_height) { + ChannelReadyStatus::ReadyToSend(channel_ready) => { + channel.unset_requires_manual_readiness_signal(); + send_channel_ready!(self, pending_msg_events, channel, channel_ready); + } + _ => return Err(APIError::APIMisuseError { err: "The channel isn't currently in a state where we can signal readiness.".to_owned() }) + } + } + hash_map::Entry::Vacant(_) => { + return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*channel_id), counterparty_node_id) }); + } + } + + Ok(()) + } + /// Gets the number of peers which match the given filter and do not have any funded, outbound, /// or 0-conf channels. /// @@ -5878,8 +5930,7 @@ where log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); - self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger) - .map(|(a, b)| (a, Vec::new(), b))); + self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), &self.node_signer, &self.default_configuration, &self.logger)); let last_best_block_height = self.best_block.read().unwrap().height(); if height < last_best_block_height { @@ -5944,9 +5995,9 @@ where self.do_chain_event(None, |channel| { if let Some(funding_txo) = channel.get_funding_txo() { if funding_txo.txid == *txid { - channel.funding_transaction_unconfirmed(&self.logger).map(|()| (None, Vec::new(), None)) - } else { Ok((None, Vec::new(), None)) } - } else { Ok((None, Vec::new(), None)) } + channel.funding_transaction_unconfirmed(&self.logger).map(|()| ChainActionUpdates::no_updates()) + } else { Ok(ChainActionUpdates::no_updates()) } + } else { Ok(ChainActionUpdates::no_updates()) } }); } } @@ -5965,7 +6016,7 @@ where /// Calls a function which handles an on-chain event (blocks dis/connected, transactions /// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by /// the function. - fn do_chain_event::Signer>) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>, Option), ClosureReason>> + fn do_chain_event::Signer>) -> Result> (&self, height_opt: Option, f: FN) { // Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called // during initialization prior to the chain_monitor being fully configured in some cases. @@ -5981,13 +6032,13 @@ where let pending_msg_events = &mut peer_state.pending_msg_events; peer_state.channel_by_id.retain(|_, channel| { let res = f(channel); - if let Ok((channel_ready_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res { - for (source, payment_hash) in timed_out_pending_htlcs.drain(..) { + if let Ok(mut chain_action_updates) = res { + for (source, payment_hash) in chain_action_updates.timed_out_htlcs.drain(..) { let (failure_code, data) = self.get_htlc_inbound_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel); timed_out_htlcs.push((source, payment_hash, HTLCFailReason::reason(failure_code, data), HTLCDestination::NextHopChannel { node_id: Some(channel.get_counterparty_node_id()), channel_id: channel.channel_id() })); } - if let Some(channel_ready) = channel_ready_opt { + if let Some(channel_ready) = chain_action_updates.channel_ready_msg { send_channel_ready!(self, pending_msg_events, channel, channel_ready); if channel.is_usable() { log_trace!(self.logger, "Sending channel_ready with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id())); @@ -6002,9 +6053,13 @@ where } } + if chain_action_updates.pending_channel_ready { + emit_pending_channel_ready_event!(self, channel); + } + emit_channel_ready_event!(self, channel); - if let Some(announcement_sigs) = announcement_sigs { + if let Some(announcement_sigs) = chain_action_updates.announcement_sigs { log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.channel_id())); pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures { node_id: channel.get_counterparty_node_id(), diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index ec34f532289..f59218369ae 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -149,6 +149,17 @@ pub struct ChannelHandshakeConfig { /// Maximum value: 1,000,000, any values larger than 1 Million will be treated as 1 Million (or 100%) /// instead, although channel negotiations will fail in that case. pub their_channel_reserve_proportional_millionths: u32, + /// If this is set to true, the user needs to manually signal readiness for an inbound channel. + /// + /// When set to true, [`Event::PendingChannelReady`] will be triggered once LDK has seen sufficient + /// confirmations of the funding transaction. In that case, a [`msgs::ChannelReady`] message will not be + /// sent to the counterparty node unless the user explicitly chooses to signal readiness. + /// + /// Default value: false. + /// + /// [`Event::PendingChannelReady`]: crate::events::Event::PendingChannelReady + /// [`msgs::ChannelReady`]: crate::ln::msgs::ChannelReady + pub manually_signal_channel_ready: bool, #[cfg(anchors)] /// If set, we attempt to negotiate the `anchors_zero_fee_htlc_tx`option for outbound channels. /// @@ -183,6 +194,7 @@ impl Default for ChannelHandshakeConfig { announced_channel: false, commit_upfront_shutdown_pubkey: true, their_channel_reserve_proportional_millionths: 10_000, + manually_signal_channel_ready: false, #[cfg(anchors)] negotiate_anchors_zero_fee_htlc_tx: false, }