Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address outstanding 2077 feedback #2382

Merged
merged 7 commits into from
Jul 20, 2023

Conversation

dunxen
Copy link
Contributor

@dunxen dunxen commented Jun 28, 2023

Resolves #2360.

@codecov-commenter
Copy link

codecov-commenter commented Jun 28, 2023

Codecov Report

Patch coverage: 80.45% and project coverage change: -0.01 ⚠️

Comparison is base (f38b80a) 90.27% compared to head (107f42f) 90.26%.

❗ Current head 107f42f differs from pull request most recent head 50a6d41. Consider uploading reports for the commit 50a6d41 to get more accurate results

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2382      +/-   ##
==========================================
- Coverage   90.27%   90.26%   -0.01%     
==========================================
  Files         106      106              
  Lines       55691    55747      +56     
  Branches    55691    55747      +56     
==========================================
+ Hits        50273    50321      +48     
- Misses       5418     5426       +8     
Impacted Files Coverage Δ
lightning/src/chain/onchaintx.rs 93.05% <ø> (ø)
lightning/src/events/mod.rs 41.60% <0.00%> (-0.20%) ⬇️
lightning/src/ln/functional_test_utils.rs 88.91% <ø> (+0.18%) ⬆️
lightning/src/ln/channelmanager.rs 85.44% <73.33%> (-0.30%) ⬇️
lightning/src/ln/channel.rs 89.40% <83.33%> (-0.08%) ⬇️
lightning/src/ln/functional_tests.rs 98.25% <96.36%> (-0.02%) ⬇️

... and 2 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@dunxen dunxen marked this pull request as ready for review June 29, 2023 15:58
@TheBlueMatt TheBlueMatt added this to the 0.0.116 milestone Jun 29, 2023
Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Show resolved Hide resolved
@wpaulino
Copy link
Contributor

wpaulino commented Jul 7, 2023

I believe we don't actually need to worry about the case where we are awaiting a message from a peer for a still pending channel as we already cover that in the disconnect path (pending channels are removed). And we do disconnect peers where we've been awaiting a message for too long.

This is not the case -- we currently only have such disconnect logic on ChannelReestablish and RevokeAndAck messages. It can be extended to more messages though.

@dunxen
Copy link
Contributor Author

dunxen commented Jul 10, 2023

This is not the case -- we currently only have such disconnect logic on ChannelReestablish and RevokeAndAck messages. It can be extended to more messages though.

Thanks for pointing that out. I believe it does make sense to keep that disconnect logic in one place. And to me it also makes sense that we disconnect peers if they're not making progress on the prefunded parts of channel establishment. Even in the case where we already have funded channels with the peer it's probably best to still disconnect if they're not making progress establishing a new one, although I could be wrong.

@dunxen
Copy link
Contributor Author

dunxen commented Jul 10, 2023

Rebasing & adding disconnect logic.

lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channel.rs Outdated Show resolved Hide resolved
lightning/src/ln/functional_tests.rs Outdated Show resolved Hide resolved
@dunxen dunxen force-pushed the 2077-followups branch 3 times, most recently from 52075e7 to a2bfb87 Compare July 14, 2023 15:07
lightning/src/ln/channelmanager.rs Show resolved Hide resolved
lightning/src/ln/channel.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channel.rs Outdated Show resolved Hide resolved
@wpaulino
Copy link
Contributor

LGTM after squash

lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/events/mod.rs Outdated Show resolved Hide resolved
lightning/src/events/mod.rs Outdated Show resolved Hide resolved
@dunxen
Copy link
Contributor Author

dunxen commented Jul 18, 2023

Rebased and squashed with:

  • pending_context -> unfunded_context
  • A move of the import for UnfundedChannelContext
  • @jkczyz's latest feedback resolved
 1:  c93b709d =  1:  3294c678 Add missing unfunded channel maps checks in `ChannelManager`
 2:  b10127c1 <  -:  -------- Fallback `close_channel_internal` to force close unfunded channels
 3:  42d78374 <  -:  -------- f avoid excess map lookups & lockorder assertions
 -:  -------- >  2:  0d6e3033 Fallback `close_channel_internal` to force close unfunded channels
 4:  a68d556e !  3:  ea515daf Consider all channel maps in `update_partial_channel_config`
    @@ lightning/src/ln/channelmanager.rs: where
     +			} else if let Some(channel) = peer_state.outbound_v1_channel_by_id.get_mut(channel_id) {
     +				&mut channel.context
     +			} else {
    ++				// This should not be reachable as we've already checked for non-existence in the previous channel_id loop.
    ++				debug_assert!(false);
     +				return Err(APIError::ChannelUnavailable {
    -+					err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", log_bytes!(*channel_id), counterparty_node_id),
    ++					err: format!(
    ++						"Channel with ID {} for passed counterparty_node_id {} disappeared after we confirmed its existence - this should not be reachable!",
    ++						log_bytes!(*channel_id), counterparty_node_id),
      				});
     -			}
     +			};
 5:  ecb44f40 <  -:  -------- f debug_assert false unreachable non-existence
 6:  c9ca69e0 !  4:  b4881d99 Force close pending channels in `internal_shutdown`
    @@ Metadata
      ## Commit message ##
         Force close pending channels in `internal_shutdown`
     
    + ## lightning/src/events/mod.rs ##
    +@@ lightning/src/events/mod.rs: impl_writeable_tlv_based_enum_upgradable!(PathFailure,
    + );
    + 
    + #[derive(Clone, Debug, PartialEq, Eq)]
    +-/// The reason the channel was closed. See individual variants more details.
    ++/// The reason the channel was closed. See individual variants for more details.
    + pub enum ClosureReason {
    + 	/// Closure generated from receiving a peer error message.
    + 	///
    +@@ lightning/src/events/mod.rs: pub enum ClosureReason {
    + 	///
    + 	/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
    + 	/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
    +-	OutdatedChannelManager
    ++	OutdatedChannelManager,
    ++	/// The counterparty requested a cooperative close of a channel that had not been funded yet.
    ++	/// The channel has been immediately closed.
    ++	CounterpartyCoopClosedUnfundedChannel,
    + }
    + 
    + impl core::fmt::Display for ClosureReason {
    +@@ lightning/src/events/mod.rs: impl core::fmt::Display for ClosureReason {
    + 			},
    + 			ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
    + 			ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
    ++			ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the prefunded channel be closed"),
    + 		}
    + 	}
    + }
    +@@ lightning/src/events/mod.rs: impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
    + 	(8, ProcessingError) => { (1, err, required) },
    + 	(10, DisconnectedPeer) => {},
    + 	(12, OutdatedChannelManager) => {},
    ++	(13, CounterpartyCoopClosedUnfundedChannel) => {},
    + );
    + 
    + /// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
    +
      ## lightning/src/ln/channelmanager.rs ##
     @@ lightning/src/ln/channelmanager.rs: where
      				})?;
    @@ lightning/src/ln/channelmanager.rs: where
     -					let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
     -						chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
     -					dropped_htlcs = htlcs;
    ++			// TODO(dunxen): Fix this duplication when we switch to a single map with enums as per
    ++			// https://github.com/lightningdevkit/rust-lightning/issues/2422
     +			if let hash_map::Entry::Occupied(chan_entry) = peer_state.outbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
    -+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(&msg.channel_id[..]));
    -+				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::HolderForceClosed);
    ++				log_error!(self.logger, "Immediately closing prefunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
    ++				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
     +				let mut chan = remove_channel!(self, chan_entry);
     +				self.finish_force_close_channel(chan.context.force_shutdown(false));
     +				return Ok(());
     +			} else if let hash_map::Entry::Occupied(chan_entry) = peer_state.inbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
    -+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(&msg.channel_id[..]));
    -+				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::HolderForceClosed);
    ++				log_error!(self.logger, "Immediately closing prefunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
    ++				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
     +				let mut chan = remove_channel!(self, chan_entry);
     +				self.finish_force_close_channel(chan.context.force_shutdown(false));
     +				return Ok(());
 7:  754c5a53 <  -:  -------- f add ClosureReason::CounterpartyCoopClosedPrefundedChannel
 8:  5996af18 =  5:  250690af Remove redundant 'outbound' wording from methods
 9:  c446ae5c !  6:  107f42f3 Close and remove unfunded inbound/outbound channels that are older than an hour
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> Channel<S
      /// A not-yet-funded outbound (from holder) channel using V1 channel establishment.
      pub(super) struct OutboundV1Channel<Signer: ChannelSigner> {
      	pub context: ChannelContext<Signer>,
    -+	pub pending_context: UnfundedChannelContext,
    ++	pub unfunded_context: UnfundedChannelContext,
      }
      
      impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> OutboundV
      				blocked_monitor_updates: Vec::new(),
     -			}
     +			},
    -+			pending_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
    ++			unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
      		})
      	}
      
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> OutboundV
      /// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment.
      pub(super) struct InboundV1Channel<Signer: ChannelSigner> {
      	pub context: ChannelContext<Signer>,
    -+	pub pending_context: UnfundedChannelContext,
    ++	pub unfunded_context: UnfundedChannelContext,
      }
      
      impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> InboundV1
      				blocked_monitor_updates: Vec::new(),
     -			}
     +			},
    -+			pending_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
    ++			unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
      		};
      
      		Ok(chan)
     
      ## lightning/src/ln/channelmanager.rs ##
    +@@ lightning/src/ln/channelmanager.rs: 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, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
    ++use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
    + use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
    + #[cfg(any(feature = "_test_utils", test))]
    + use crate::ln::features::Bolt11InvoiceFeatures;
     @@ lightning/src/ln/channelmanager.rs: where
      	///  * Expiring a channel's previous [`ChannelConfig`] if necessary to only allow forwarding HTLCs
      	///    with the current [`ChannelConfig`].
    @@ lightning/src/ln/channelmanager.rs: where
      						true
      					});
     +
    -+					let force_close_expired_unfunded_channel = |chan_id: &[u8; 32], chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>| {
    -+						log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
    -+						self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
    -+						self.finish_force_close_channel(chan_context.force_shutdown(false));
    -+						false
    -+					};
    -+					peer_state.outbound_v1_channel_by_id.retain(|chan_id, chan| {
    -+						if chan.pending_context.should_expire_unfunded_channel() {
    -+							force_close_expired_unfunded_channel(chan_id, &mut chan.context)
    ++					let process_unfunded_channel_tick = |
    ++						chan_id: &[u8; 32],
    ++						chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>,
    ++						unfunded_chan_context: &mut UnfundedChannelContext,
    ++					| {
    ++						chan_context.maybe_expire_prev_config();
    ++						if unfunded_chan_context.should_expire_unfunded_channel() {
    ++							log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
    ++							update_maps_on_chan_removal!(self, &chan_context);
    ++							self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
    ++							self.finish_force_close_channel(chan_context.force_shutdown(false));
    ++							false
     +						} else {
     +							true
     +						}
    -+					});
    -+					peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| {
    -+						if chan.pending_context.should_expire_unfunded_channel() {
    -+							force_close_expired_unfunded_channel(chan_id, &mut chan.context)
    -+						} else {
    -+							true
    -+						}
    -+					});
    ++					};
    ++					peer_state.outbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
    ++					peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
     +
      					if peer_state.ok_to_remove(true) {
      						pending_peers_awaiting_removal.push(counterparty_node_id);
10:  1c8ef1bf <  -:  -------- f missing calls in tick

@jkczyz
Copy link
Contributor

jkczyz commented Jul 18, 2023

Rebased and squashed with:

  • pending_context -> unfunded_context
  • A move of the import for UnfundedChannelContext
  • @jkczyz's latest feedback resolved
 1:  c93b709d =  1:  3294c678 Add missing unfunded channel maps checks in `ChannelManager`
 2:  b10127c1 <  -:  -------- Fallback `close_channel_internal` to force close unfunded channels
 3:  42d78374 <  -:  -------- f avoid excess map lookups & lockorder assertions
 -:  -------- >  2:  0d6e3033 Fallback `close_channel_internal` to force close unfunded channels
 4:  a68d556e !  3:  ea515daf Consider all channel maps in `update_partial_channel_config`
    @@ lightning/src/ln/channelmanager.rs: where
     +			} else if let Some(channel) = peer_state.outbound_v1_channel_by_id.get_mut(channel_id) {
     +				&mut channel.context
     +			} else {
    ++				// This should not be reachable as we've already checked for non-existence in the previous channel_id loop.
    ++				debug_assert!(false);
     +				return Err(APIError::ChannelUnavailable {
    -+					err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", log_bytes!(*channel_id), counterparty_node_id),
    ++					err: format!(
    ++						"Channel with ID {} for passed counterparty_node_id {} disappeared after we confirmed its existence - this should not be reachable!",
    ++						log_bytes!(*channel_id), counterparty_node_id),
      				});
     -			}
     +			};
 5:  ecb44f40 <  -:  -------- f debug_assert false unreachable non-existence
 6:  c9ca69e0 !  4:  b4881d99 Force close pending channels in `internal_shutdown`
    @@ Metadata
      ## Commit message ##
         Force close pending channels in `internal_shutdown`
     
    + ## lightning/src/events/mod.rs ##
    +@@ lightning/src/events/mod.rs: impl_writeable_tlv_based_enum_upgradable!(PathFailure,
    + );
    + 
    + #[derive(Clone, Debug, PartialEq, Eq)]
    +-/// The reason the channel was closed. See individual variants more details.
    ++/// The reason the channel was closed. See individual variants for more details.
    + pub enum ClosureReason {
    + 	/// Closure generated from receiving a peer error message.
    + 	///
    +@@ lightning/src/events/mod.rs: pub enum ClosureReason {
    + 	///
    + 	/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
    + 	/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
    +-	OutdatedChannelManager
    ++	OutdatedChannelManager,
    ++	/// The counterparty requested a cooperative close of a channel that had not been funded yet.
    ++	/// The channel has been immediately closed.
    ++	CounterpartyCoopClosedUnfundedChannel,
    + }
    + 
    + impl core::fmt::Display for ClosureReason {
    +@@ lightning/src/events/mod.rs: impl core::fmt::Display for ClosureReason {
    + 			},
    + 			ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
    + 			ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
    ++			ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the prefunded channel be closed"),
    + 		}
    + 	}
    + }
    +@@ lightning/src/events/mod.rs: impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
    + 	(8, ProcessingError) => { (1, err, required) },
    + 	(10, DisconnectedPeer) => {},
    + 	(12, OutdatedChannelManager) => {},
    ++	(13, CounterpartyCoopClosedUnfundedChannel) => {},
    + );
    + 
    + /// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].
    +
      ## lightning/src/ln/channelmanager.rs ##
     @@ lightning/src/ln/channelmanager.rs: where
      				})?;
    @@ lightning/src/ln/channelmanager.rs: where
     -					let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
     -						chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
     -					dropped_htlcs = htlcs;
    ++			// TODO(dunxen): Fix this duplication when we switch to a single map with enums as per
    ++			// https://github.com/lightningdevkit/rust-lightning/issues/2422
     +			if let hash_map::Entry::Occupied(chan_entry) = peer_state.outbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
    -+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(&msg.channel_id[..]));
    -+				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::HolderForceClosed);
    ++				log_error!(self.logger, "Immediately closing prefunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
    ++				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
     +				let mut chan = remove_channel!(self, chan_entry);
     +				self.finish_force_close_channel(chan.context.force_shutdown(false));
     +				return Ok(());
     +			} else if let hash_map::Entry::Occupied(chan_entry) = peer_state.inbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
    -+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(&msg.channel_id[..]));
    -+				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::HolderForceClosed);
    ++				log_error!(self.logger, "Immediately closing prefunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
    ++				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
     +				let mut chan = remove_channel!(self, chan_entry);
     +				self.finish_force_close_channel(chan.context.force_shutdown(false));
     +				return Ok(());
 7:  754c5a53 <  -:  -------- f add ClosureReason::CounterpartyCoopClosedPrefundedChannel
 8:  5996af18 =  5:  250690af Remove redundant 'outbound' wording from methods
 9:  c446ae5c !  6:  107f42f3 Close and remove unfunded inbound/outbound channels that are older than an hour
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> Channel<S
      /// A not-yet-funded outbound (from holder) channel using V1 channel establishment.
      pub(super) struct OutboundV1Channel<Signer: ChannelSigner> {
      	pub context: ChannelContext<Signer>,
    -+	pub pending_context: UnfundedChannelContext,
    ++	pub unfunded_context: UnfundedChannelContext,
      }
      
      impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> OutboundV
      				blocked_monitor_updates: Vec::new(),
     -			}
     +			},
    -+			pending_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
    ++			unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
      		})
      	}
      
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> OutboundV
      /// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment.
      pub(super) struct InboundV1Channel<Signer: ChannelSigner> {
      	pub context: ChannelContext<Signer>,
    -+	pub pending_context: UnfundedChannelContext,
    ++	pub unfunded_context: UnfundedChannelContext,
      }
      
      impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
    @@ lightning/src/ln/channel.rs: impl<Signer: WriteableEcdsaChannelSigner> InboundV1
      				blocked_monitor_updates: Vec::new(),
     -			}
     +			},
    -+			pending_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
    ++			unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
      		};
      
      		Ok(chan)
     
      ## lightning/src/ln/channelmanager.rs ##
    +@@ lightning/src/ln/channelmanager.rs: 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, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
    ++use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
    + use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
    + #[cfg(any(feature = "_test_utils", test))]
    + use crate::ln::features::Bolt11InvoiceFeatures;
     @@ lightning/src/ln/channelmanager.rs: where
      	///  * Expiring a channel's previous [`ChannelConfig`] if necessary to only allow forwarding HTLCs
      	///    with the current [`ChannelConfig`].
    @@ lightning/src/ln/channelmanager.rs: where
      						true
      					});
     +
    -+					let force_close_expired_unfunded_channel = |chan_id: &[u8; 32], chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>| {
    -+						log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
    -+						self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
    -+						self.finish_force_close_channel(chan_context.force_shutdown(false));
    -+						false
    -+					};
    -+					peer_state.outbound_v1_channel_by_id.retain(|chan_id, chan| {
    -+						if chan.pending_context.should_expire_unfunded_channel() {
    -+							force_close_expired_unfunded_channel(chan_id, &mut chan.context)
    ++					let process_unfunded_channel_tick = |
    ++						chan_id: &[u8; 32],
    ++						chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>,
    ++						unfunded_chan_context: &mut UnfundedChannelContext,
    ++					| {
    ++						chan_context.maybe_expire_prev_config();
    ++						if unfunded_chan_context.should_expire_unfunded_channel() {
    ++							log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
    ++							update_maps_on_chan_removal!(self, &chan_context);
    ++							self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
    ++							self.finish_force_close_channel(chan_context.force_shutdown(false));
    ++							false
     +						} else {
     +							true
     +						}
    -+					});
    -+					peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| {
    -+						if chan.pending_context.should_expire_unfunded_channel() {
    -+							force_close_expired_unfunded_channel(chan_id, &mut chan.context)
    -+						} else {
    -+							true
    -+						}
    -+					});
    ++					};
    ++					peer_state.outbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
    ++					peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));
     +
      					if peer_state.ok_to_remove(true) {
      						pending_peers_awaiting_removal.push(counterparty_node_id);
10:  1c8ef1bf <  -:  -------- f missing calls in tick

The Display string and error logging are still using "prefunded".

@dunxen
Copy link
Contributor Author

dunxen commented Jul 18, 2023

Just changed some occurrences of "prefunded" to "unfunded" in first commit.

EDIT: Ugh. Missed the actual ones Jeff pointed out. Fixed now.

@jkczyz
Copy link
Contributor

jkczyz commented Jul 18, 2023

Just changed some occurrences of "prefunded" to "unfunded" in first commit.

EDIT: Ugh. Missed the actual ones Jeff pointed out. Fixed now.

FWIW, regarding the commit message and change, I'm indifferent to use of "pending". I primarily thought "prefunded" wasn't accurate.

jkczyz
jkczyz previously approved these changes Jul 18, 2023
lightning/src/ln/channel.rs Outdated Show resolved Hide resolved
@dunxen
Copy link
Contributor Author

dunxen commented Jul 18, 2023

Just changed some occurrences of "prefunded" to "unfunded" in first commit.
EDIT: Ugh. Missed the actual ones Jeff pointed out. Fixed now.

FWIW, regarding the commit message and change, I'm indifferent to use of "pending". I primarily thought "prefunded" wasn't accurate.

@wpaulino pointed out that pending is a little ambiguous, which I agree with as it might refer to "pending confirmation". So "unfunded" is the best short name we're going to get :)

wpaulino
wpaulino previously approved these changes Jul 18, 2023
We had some inconsistencies so far in referring to channels such as
`OutboundV1Channel` and `InboundV1Channel` as pending and unfunded.
From here we refer to these kinds of channels only as "unfunded".

This is a slight conflation with the term "unfunded" in the contexts
of denial of service mitigation. There, "unfunded" actually refers to
non-0conf, inbound channels that have not had their funding transaction
confirmed. This might warrant changing that usage to "unconfirmed inbound".
One of a series of follow-up commits to address some issues found
in PR 2077, where we split channels up into different maps and structs
depending on phase in their life.
…an an hour

We introduce a `UnfundedChannelContext` which contains a counter for the
current age of an unfunded channel in timer ticks. This age is incremented
for every `ChannelManager::timer_tick_ocurred` and the unfunded channel
is removed if it exceeds `UNFUNDED_CHANNEL_AGE_LIMIT_TICKS`.

The value will not be persisted as unfunded channels themselves are not
persisted.
@dunxen
Copy link
Contributor Author

dunxen commented Jul 19, 2023

Rebased and changed the one occurrence of "pending" to "unfunded" that Jeff pointed out.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#2077 (comment) and #2077 (comment) should still be addressed, but certainly aren't release blocking or blocking this PR.

@@ -7226,37 +7295,20 @@ where
log_debug!(self.logger, "Generating channel_reestablish events for {}", log_pubkey!(counterparty_node_id));

let per_peer_state = self.per_peer_state.read().unwrap();
for (_cp_id, peer_state_mutex) in per_peer_state.iter() {
if let Some(peer_state_mutex) = per_peer_state.get(counterparty_node_id) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦 Oh lol I missed we were changing this to no longer iterate, which is actually what introduces #2418. That's okay, I think we should stop iterating all our peers when any peer connects, and should move the rebroadcast code elsewhere anyway.

peer_state.channel_by_id.retain(|_, chan| {
let retain = if chan.context.get_counterparty_node_id() == *counterparty_node_id {
if !chan.context.have_received_message() {
// If we created this (outbound) channel while we were disconnected from the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing where we discussed this no longer being true - while its not a big deal cause they'll eventually time out anyway, we should still be clearing the inbound/outbound sets on peer connection, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can’t think of a situation where inbound / outbound sets wouldn’t be empty upon reconnect. We clear them on disconnect and they’re never persisted so aren’t recoverable after a crash. Or I might be missing a case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't currently check if the peer is connected in create_channel, so will happily create a channel, fail to send an OpenChannel, and let it sit around waiting for the peer to connect. At the time we didn't track if peers were connected in ChannelManager, but now that we do we should really fix that issue by failing early in create_channel, rather than leaning on peer_connected to miraculously fail the channel. We should do that later, though.

@TheBlueMatt TheBlueMatt merged commit 16311f9 into lightningdevkit:main Jul 20, 2023
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2077 Followups
5 participants