+#[derive(Clone, Debug, PartialEq)]
+/// The reason the channel was closed. See individual variants more details.
+pub enum ClosureReason {
+ /// Closure generated from receiving a peer error message.
+ ///
+ /// Our counterparty may have broadcasted their latest commitment state, and we have
+ /// as well.
+ CounterpartyForceClosed {
+ /// The error which the peer sent us.
+ ///
+ /// The string should be sanitized before it is used (e.g emitted to logs
+ /// or printed to stdout). Otherwise, a well crafted error message may exploit
+ /// a security vulnerability in the terminal emulator or the logging subsystem.
+ peer_msg: String,
+ },
+ /// Closure generated from [`ChannelManager::force_close_channel`], called by the user.
+ ///
+ /// [`ChannelManager::force_close_channel`]: crate::ln::channelmanager::ChannelManager::force_close_channel.
+ HolderForceClosed,
+ /// The channel was closed after negotiating a cooperative close and we've now broadcasted
+ /// the cooperative close transaction. Note the shutdown may have been initiated by us.
+ //TODO: split between CounterpartyInitiated/LocallyInitiated
+ CooperativeClosure,
+ /// A commitment transaction was confirmed on chain, closing the channel. Most likely this
+ /// commitment transaction came from our counterparty, but it may also have come from
+ /// a copy of our own `ChannelMonitor`.
+ CommitmentTxConfirmed,
+ /// The funding transaction failed to confirm in a timely manner on an inbound channel.
+ FundingTimedOut,
+ /// Closure generated from processing an event, likely a HTLC forward/relay/reception.
+ ProcessingError {
+ /// A developer-readable error message which we generated.
+ err: String,
+ },
+ /// The `PeerManager` informed us that we've disconnected from the peer. We close channels
+ /// if the `PeerManager` informed us that it is unlikely we'll be able to connect to the
+ /// peer again in the future or if the peer disconnected before we finished negotiating
+ /// the channel open. The first case may be caused by incompatible features which our
+ /// counterparty, or we, require.
+ //TODO: split between PeerUnconnectable/PeerDisconnected ?
+ DisconnectedPeer,
+ /// Closure generated from `ChannelManager::read` if the ChannelMonitor is newer than
+ /// the ChannelManager deserialized.
+ OutdatedChannelManager
+}
+
+impl core::fmt::Display for ClosureReason {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
+ f.write_str("Channel closed because ")?;
+ match self {
+ ClosureReason::CounterpartyForceClosed { peer_msg } => {
+ f.write_str("counterparty force-closed with message ")?;
+ f.write_str(&peer_msg)
+ },
+ ClosureReason::HolderForceClosed => f.write_str("user manually force-closed the channel"),
+ ClosureReason::CooperativeClosure => f.write_str("the channel was cooperatively closed"),
+ ClosureReason::CommitmentTxConfirmed => f.write_str("commitment or closing transaction was confirmed on chain."),
+ ClosureReason::FundingTimedOut => write!(f, "funding transaction failed to confirm within {} blocks", FUNDING_CONF_DEADLINE_BLOCKS),
+ ClosureReason::ProcessingError { err } => {
+ f.write_str("of an exception: ")?;
+ f.write_str(&err)
+ },
+ 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)"),
+ }
+ }
+}
+
+impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
+ (0, CounterpartyForceClosed) => { (1, peer_msg, required) },
+ (1, FundingTimedOut) => {},
+ (2, HolderForceClosed) => {},
+ (6, CommitmentTxConfirmed) => {},
+ (4, CooperativeClosure) => {},
+ (8, ProcessingError) => { (1, err, required) },
+ (10, DisconnectedPeer) => {},
+ (12, OutdatedChannelManager) => {},
+);
+