Merge pull request #2347 from henghonglee/issue-2304
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Fri, 7 Jul 2023 21:21:09 +0000 (21:21 +0000)
committerGitHub <noreply@github.com>
Fri, 7 Jul 2023 21:21:09 +0000 (21:21 +0000)
Expose whether a channel is closing in ChannelDetails

1  2 
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/routing/router.rs

index 30280f0b1f131a45a883f7b292a2cc3cadbb0997,680757bae1b7bccb87449de6ded7310af3bfc71c..535106954228d2f7149db8d1f29cdad75096bf6c
@@@ -27,7 -27,7 +27,7 @@@ use crate::ln::features::{ChannelTypeFe
  use crate::ln::msgs;
  use crate::ln::msgs::DecodeError;
  use crate::ln::script::{self, ShutdownScript};
- use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+ use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT, ChannelShutdownState};
  use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
  use crate::ln::chan_utils;
  use crate::ln::onion_utils::HTLCFailReason;
@@@ -903,6 -903,34 +903,34 @@@ impl<Signer: ChannelSigner> ChannelCont
                (self.channel_state & mask) == (ChannelState::ChannelReady as u32) && !self.monitor_pending_channel_ready
        }
  
+       /// shutdown state returns the state of the channel in its various stages of shutdown
+       pub fn shutdown_state(&self) -> ChannelShutdownState {
+               if self.channel_state & (ChannelState::ShutdownComplete as u32) != 0 {
+                       return ChannelShutdownState::ShutdownComplete;
+               }
+               if self.channel_state & (ChannelState::LocalShutdownSent as u32) != 0 &&  self.channel_state & (ChannelState::RemoteShutdownSent as u32) == 0 {
+                       return ChannelShutdownState::ShutdownInitiated;
+               }
+               if (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0) && !self.closing_negotiation_ready() {
+                       return ChannelShutdownState::ResolvingHTLCs;
+               }
+               if (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0) && self.closing_negotiation_ready() {
+                       return ChannelShutdownState::NegotiatingClosingFee;
+               }
+               return ChannelShutdownState::NotShuttingDown;
+       }
+       fn closing_negotiation_ready(&self) -> bool {
+               self.pending_inbound_htlcs.is_empty() &&
+               self.pending_outbound_htlcs.is_empty() &&
+               self.pending_update_fee.is_none() &&
+               self.channel_state &
+               (BOTH_SIDES_SHUTDOWN_MASK |
+                       ChannelState::AwaitingRemoteRevoke as u32 |
+                       ChannelState::PeerDisconnected as u32 |
+                       ChannelState::MonitorUpdateInProgress as u32) == BOTH_SIDES_SHUTDOWN_MASK
+       }
        /// Returns true if this channel is currently available for use. This is a superset of
        /// is_usable() and considers things like the channel being temporarily disabled.
        /// Allowed in any state (including after shutdown)
@@@ -3956,12 -3984,7 +3984,7 @@@ impl<Signer: WriteableEcdsaChannelSigne
        /// this point if we're the funder we should send the initial closing_signed, and in any case
        /// shutdown should complete within a reasonable timeframe.
        fn closing_negotiation_ready(&self) -> bool {
-               self.context.pending_inbound_htlcs.is_empty() && self.context.pending_outbound_htlcs.is_empty() &&
-                       self.context.channel_state &
-                               (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::AwaitingRemoteRevoke as u32 |
-                                ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)
-                               == BOTH_SIDES_SHUTDOWN_MASK &&
-                       self.context.pending_update_fee.is_none()
+               self.context.closing_negotiation_ready()
        }
  
        /// Checks if the closing_signed negotiation is making appropriate progress, possibly returning
@@@ -6781,7 -6804,6 +6804,7 @@@ impl<Signer: WriteableEcdsaChannelSigne
                        (5, self.context.config, required),
                        (6, serialized_holder_htlc_max_in_flight, option),
                        (7, self.context.shutdown_scriptpubkey, option),
 +                      (8, self.context.blocked_monitor_updates, vec_type),
                        (9, self.context.target_closing_feerate_sats_per_kw, option),
                        (11, self.context.monitor_pending_finalized_fulfills, vec_type),
                        (13, self.context.channel_creation_height, required),
                        (28, holder_max_accepted_htlcs, option),
                        (29, self.context.temporary_channel_id, option),
                        (31, channel_pending_event_emitted, option),
 -                      (33, self.context.blocked_monitor_updates, vec_type),
                        (35, pending_outbound_skimmed_fees, optional_vec),
                        (37, holding_cell_skimmed_fees, optional_vec),
                });
@@@ -7089,7 -7112,6 +7112,7 @@@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> 
                        (5, config, option), // Note that if none is provided we will *not* overwrite the existing one.
                        (6, holder_max_htlc_value_in_flight_msat, option),
                        (7, shutdown_scriptpubkey, option),
 +                      (8, blocked_monitor_updates, vec_type),
                        (9, target_closing_feerate_sats_per_kw, option),
                        (11, monitor_pending_finalized_fulfills, vec_type),
                        (13, channel_creation_height, option),
                        (28, holder_max_accepted_htlcs, option),
                        (29, temporary_channel_id, option),
                        (31, channel_pending_event_emitted, option),
 -                      (33, blocked_monitor_updates, vec_type),
                        (35, pending_outbound_skimmed_fees_opt, optional_vec),
                        (37, holding_cell_skimmed_fees_opt, optional_vec),
                });
index 980616770c87e75fa4580f83c641a35b2b5fc97f,d18e6537da0a98d7c1f338781e9c47f165f4779e..fcf71bb3f25b205fb7920b028a9d01308952a84f
@@@ -752,23 -752,7 +752,23 @@@ pub type SimpleArcChannelManager<M, T, 
  /// of [`KeysManager`] and [`DefaultRouter`].
  ///
  /// This is not exported to bindings users as Arcs don't make sense in bindings
 -pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> = ChannelManager<&'a M, &'b T, &'c KeysManager, &'c KeysManager, &'c KeysManager, &'d F, &'e DefaultRouter<&'f NetworkGraph<&'g L>, &'g L, &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, ProbabilisticScoringFeeParameters, ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>, &'g L>;
 +pub type SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L> =
 +      ChannelManager<
 +              &'a M,
 +              &'b T,
 +              &'c KeysManager,
 +              &'c KeysManager,
 +              &'c KeysManager,
 +              &'d F,
 +              &'e DefaultRouter<
 +                      &'f NetworkGraph<&'g L>,
 +                      &'g L,
 +                      &'h Mutex<ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>>,
 +                      ProbabilisticScoringFeeParameters,
 +                      ProbabilisticScorer<&'f NetworkGraph<&'g L>, &'g L>
 +              >,
 +              &'g L
 +      >;
  
  macro_rules! define_test_pub_trait { ($vis: vis) => {
  /// A trivial trait which describes any [`ChannelManager`] used in testing.
@@@ -1480,6 -1464,9 +1480,9 @@@ pub struct ChannelDetails 
        ///
        /// [`confirmations_required`]: ChannelDetails::confirmations_required
        pub is_channel_ready: bool,
+       /// The stage of the channel's shutdown.
+       /// `None` for `ChannelDetails` serialized on LDK versions prior to 0.0.116.
+       pub channel_shutdown_state: Option<ChannelShutdownState>,
        /// True if the channel is (a) confirmed and channel_ready messages have been exchanged, (b)
        /// the peer is connected, and (c) the channel is not currently negotiating a shutdown.
        ///
@@@ -1567,10 -1554,33 +1570,33 @@@ impl ChannelDetails 
                        inbound_htlc_minimum_msat: Some(context.get_holder_htlc_minimum_msat()),
                        inbound_htlc_maximum_msat: context.get_holder_htlc_maximum_msat(),
                        config: Some(context.config()),
+                       channel_shutdown_state: Some(context.shutdown_state()),
                }
        }
  }
  
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ /// Further information on the details of the channel shutdown.
+ /// Upon channels being forced closed (i.e. commitment transaction confirmation detected
+ /// by `ChainMonitor`), ChannelShutdownState will be set to `ShutdownComplete` or
+ /// the channel will be removed shortly.
+ /// Also note, that in normal operation, peers could disconnect at any of these states
+ /// and require peer re-connection before making progress onto other states
+ pub enum ChannelShutdownState {
+       /// Channel has not sent or received a shutdown message.
+       NotShuttingDown,
+       /// Local node has sent a shutdown message for this channel.
+       ShutdownInitiated,
+       /// Shutdown message exchanges have concluded and the channels are in the midst of
+       /// resolving all existing open HTLCs before closing can continue.
+       ResolvingHTLCs,
+       /// All HTLCs have been resolved, nodes are currently negotiating channel close onchain fee rates.
+       NegotiatingClosingFee,
+       /// We've successfully negotiated a closing_signed dance. At this point `ChannelManager` is about
+       /// to drop the channel.
+       ShutdownComplete,
+ }
  /// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
  /// These include payments that have yet to find a successful path, or have unresolved HTLCs.
  #[derive(Debug, PartialEq)]
@@@ -7365,6 -7375,7 +7391,7 @@@ impl Writeable for ChannelDetails 
                        (35, self.inbound_htlc_maximum_msat, option),
                        (37, user_channel_id_high_opt, option),
                        (39, self.feerate_sat_per_1000_weight, option),
+                       (41, self.channel_shutdown_state, option),
                });
                Ok(())
        }
@@@ -7402,6 -7413,7 +7429,7 @@@ impl Readable for ChannelDetails 
                        (35, inbound_htlc_maximum_msat, option),
                        (37, user_channel_id_high_opt, option),
                        (39, feerate_sat_per_1000_weight, option),
+                       (41, channel_shutdown_state, option),
                });
  
                // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
                        inbound_htlc_minimum_msat,
                        inbound_htlc_maximum_msat,
                        feerate_sat_per_1000_weight,
+                       channel_shutdown_state,
                })
        }
  }
@@@ -7987,6 -8000,14 +8016,14 @@@ impl Readable for VecDeque<(Event, Opti
        }
  }
  
+ impl_writeable_tlv_based_enum!(ChannelShutdownState,
+       (0, NotShuttingDown) => {},
+       (2, ShutdownInitiated) => {},
+       (4, ResolvingHTLCs) => {},
+       (6, NegotiatingClosingFee) => {},
+       (8, ShutdownComplete) => {}, ;
+ );
  /// Arguments for the creation of a ChannelManager that are not deserialized.
  ///
  /// At a high-level, the process for deserializing a ChannelManager and resuming normal operation
index ed5b772edad3efb69aa28a5a91a707b56226fdf3,15f43d2975dcd37aae08105a0615127c29cda748..f82ddc80a11abaecf334c04a8110c9c485f696e7
@@@ -27,15 -27,15 +27,15 @@@ use crate::util::chacha20::ChaCha20
  
  use crate::io;
  use crate::prelude::*;
 -use crate::sync::{Mutex, MutexGuard};
 +use crate::sync::{Mutex};
  use alloc::collections::BinaryHeap;
  use core::{cmp, fmt};
 -use core::ops::Deref;
 +use core::ops::{Deref, DerefMut};
  
  /// A [`Router`] implemented using [`find_route`].
  pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> where
        L::Target: Logger,
 -      S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 +      S::Target: for <'a> LockableScore<'a, Score = Sc>,
  {
        network_graph: G,
        logger: L,
@@@ -46,7 -46,7 +46,7 @@@
  
  impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
 -      S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 +      S::Target: for <'a> LockableScore<'a, Score = Sc>,
  {
        /// Creates a new router.
        pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S, score_params: SP) -> Self {
@@@ -55,9 -55,9 +55,9 @@@
        }
  }
  
 -impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref,  SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
 +impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
        L::Target: Logger,
 -      S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
 +      S::Target: for <'a> LockableScore<'a, Score = Sc>,
  {
        fn find_route(
                &self,
@@@ -73,7 -73,7 +73,7 @@@
                };
                find_route(
                        payer, params, &self.network_graph, first_hops, &*self.logger,
 -                      &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock(), inflight_htlcs),
 +                      &ScorerAccountingForInFlightHtlcs::new(self.scorer.lock().deref_mut(), inflight_htlcs),
                        &self.score_params,
                        &random_seed_bytes
                )
@@@ -104,15 -104,15 +104,15 @@@ pub trait Router 
  /// [`find_route`].
  ///
  /// [`Score`]: crate::routing::scoring::Score
 -pub struct ScorerAccountingForInFlightHtlcs<'a, S: Score> {
 -      scorer: S,
 +pub struct ScorerAccountingForInFlightHtlcs<'a, S: Score<ScoreParams = SP>, SP: Sized> {
 +      scorer: &'a mut S,
        // Maps a channel's short channel id and its direction to the liquidity used up.
        inflight_htlcs: &'a InFlightHtlcs,
  }
  
 -impl<'a, S: Score> ScorerAccountingForInFlightHtlcs<'a, S> {
 +impl<'a, S: Score<ScoreParams = SP>, SP: Sized> ScorerAccountingForInFlightHtlcs<'a, S, SP> {
        /// Initialize a new `ScorerAccountingForInFlightHtlcs`.
 -      pub fn new(scorer: S, inflight_htlcs: &'a InFlightHtlcs) -> Self {
 +      pub fn new(scorer:  &'a mut S, inflight_htlcs: &'a InFlightHtlcs) -> Self {
                ScorerAccountingForInFlightHtlcs {
                        scorer,
                        inflight_htlcs
  }
  
  #[cfg(c_bindings)]
 -impl<'a, S: Score> Writeable for ScorerAccountingForInFlightHtlcs<'a, S> {
 +impl<'a, S: Score<ScoreParams = SP>, SP: Sized> Writeable for ScorerAccountingForInFlightHtlcs<'a, S, SP> {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> { self.scorer.write(writer) }
  }
  
 -impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
 +impl<'a, S: Score<ScoreParams = SP>, SP: Sized> Score for ScorerAccountingForInFlightHtlcs<'a, S, SP>  {
        type ScoreParams = S::ScoreParams;
        fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
                if let Some(used_liquidity) = self.inflight_htlcs.used_liquidity_msat(
@@@ -2687,7 -2687,8 +2687,8 @@@ mod tests 
                        inbound_htlc_minimum_msat: None,
                        inbound_htlc_maximum_msat: None,
                        config: None,
-                       feerate_sat_per_1000_weight: None
+                       feerate_sat_per_1000_weight: None,
+                       channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
                }
        }
  
@@@ -6758,6 -6759,7 +6759,7 @@@ pub(crate) mod bench_utils 
                        inbound_htlc_maximum_msat: None,
                        config: None,
                        feerate_sat_per_1000_weight: None,
+                       channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
                }
        }