Note when new HTLC state can be `None`
[rust-lightning] / lightning / src / ln / channel.rs
index 949b88637e4a1f6f81100916b0d65ced0275b2b2..31989a011a971b5dc55f170eac5e3de9e99205b2 100644 (file)
@@ -158,6 +158,72 @@ enum InboundHTLCState {
        LocalRemoved(InboundHTLCRemovalReason),
 }
 
+/// Exposes the state of pending inbound HTLCs.
+///
+/// At a high level, an HTLC being forwarded from one Lightning node to another Lightning node goes
+/// through the following states in the state machine:
+/// - Announced for addition by the originating node through the update_add_htlc message.
+/// - Added to the commitment transaction of the receiving node and originating node in turn
+///   through the exchange of commitment_signed and revoke_and_ack messages.
+/// - Announced for resolution (fulfillment or failure) by the receiving node through either one of
+///   the update_fulfill_htlc, update_fail_htlc, and update_fail_malformed_htlc messages.
+/// - Removed from the commitment transaction of the originating node and receiving node in turn
+///   through the exchange of commitment_signed and revoke_and_ack messages.
+///
+/// This can be used to inspect what next message an HTLC is waiting for to advance its state.
+#[derive(Clone, Debug, PartialEq)]
+pub enum InboundHTLCStateDetails {
+       /// We have added this HTLC in our commitment transaction by receiving commitment_signed and
+       /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
+       /// before this HTLC is included on the remote commitment transaction.
+       AwaitingRemoteRevokeToAdd,
+       /// This HTLC has been included in the commitment_signed and revoke_and_ack messages on both sides
+       /// and is included in both commitment transactions.
+       ///
+       /// This HTLC is now safe to either forward or be claimed as a payment by us. The HTLC will
+       /// remain in this state until the forwarded upstream HTLC has been resolved and we resolve this
+       /// HTLC correspondingly, or until we claim it as a payment. If it is part of a multipart
+       /// payment, it will only be claimed together with other required parts.
+       Committed,
+       /// We have received the preimage for this HTLC and it is being removed by fulfilling it with
+       /// update_fulfill_htlc. This HTLC is still on both commitment transactions, but we are awaiting
+       /// the appropriate revoke_and_ack's from the remote before this HTLC is removed from the remote
+       /// commitment transaction after update_fulfill_htlc.
+       AwaitingRemoteRevokeToRemoveFulfill,
+       /// The HTLC is being removed by failing it with update_fail_htlc or update_fail_malformed_htlc.
+       /// This HTLC is still on both commitment transactions, but we are awaiting the appropriate
+       /// revoke_and_ack's from the remote before this HTLC is removed from the remote commitment
+       /// transaction.
+       AwaitingRemoteRevokeToRemoveFail,
+}
+
+impl From<&InboundHTLCState> for Option<InboundHTLCStateDetails> {
+       fn from(state: &InboundHTLCState) -> Option<InboundHTLCStateDetails> {
+               match state {
+                       InboundHTLCState::RemoteAnnounced(_) => None,
+                       InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) =>
+                               Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToAdd),
+                       InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) =>
+                               Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToAdd),
+                       InboundHTLCState::Committed =>
+                               Some(InboundHTLCStateDetails::Committed),
+                       InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(_)) =>
+                               Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail),
+                       InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed(_)) =>
+                               Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail),
+                       InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) =>
+                               Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFulfill),
+               }
+       }
+}
+
+impl_writeable_tlv_based_enum_upgradable!(InboundHTLCStateDetails,
+       (0, AwaitingRemoteRevokeToAdd) => {},
+       (2, Committed) => {},
+       (4, AwaitingRemoteRevokeToRemoveFulfill) => {},
+       (6, AwaitingRemoteRevokeToRemoveFail) => {};
+);
+
 struct InboundHTLCOutput {
        htlc_id: u64,
        amount_msat: u64,
@@ -166,6 +232,53 @@ struct InboundHTLCOutput {
        state: InboundHTLCState,
 }
 
+/// Exposes details around pending inbound HTLCs.
+#[derive(Clone, Debug, PartialEq)]
+pub struct InboundHTLCDetails {
+       /// The HTLC ID.
+       /// The IDs are incremented by 1 starting from 0 for each offered HTLC.
+       /// They are unique per channel and inbound/outbound direction, unless an HTLC was only announced
+       /// and not part of any commitment transaction.
+       pub htlc_id: u64,
+       /// The amount in msat.
+       pub amount_msat: u64,
+       /// The block height at which this HTLC expires.
+       pub cltv_expiry: u32,
+       /// The payment hash.
+       pub payment_hash: PaymentHash,
+       /// The state of the HTLC in the state machine.
+       ///
+       /// Determines on which commitment transactions the HTLC is included and what message the HTLC is
+       /// waiting for to advance to the next state.
+       ///
+       /// See [`InboundHTLCStateDetails`] for information on the specific states.
+       ///
+       /// LDK will always fill this field in, but when downgrading to prior versions of LDK, new
+       /// states may result in `None` here.
+       pub state: Option<InboundHTLCStateDetails>,
+       /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
+       /// from the local commitment transaction and added to the commitment transaction fee.
+       /// For non-anchor channels, this takes into account the cost of the second-stage HTLC
+       /// transactions as well.
+       ///
+       /// When the local commitment transaction is broadcasted as part of a unilateral closure,
+       /// the value of this HTLC will therefore not be claimable but instead burned as a transaction
+       /// fee.
+       ///
+       /// Note that dust limits are specific to each party. An HTLC can be dust for the local
+       /// commitment transaction but not for the counterparty's commitment transaction and vice versa.
+       pub is_dust: bool,
+}
+
+impl_writeable_tlv_based!(InboundHTLCDetails, {
+       (0, htlc_id, required),
+       (2, amount_msat, required),
+       (4, cltv_expiry, required),
+       (6, payment_hash, required),
+       (7, state, upgradable_option),
+       (8, is_dust, required),
+});
+
 #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
 enum OutboundHTLCState {
        /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
@@ -199,6 +312,72 @@ enum OutboundHTLCState {
        AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
 }
 
+/// Exposes the state of pending outbound HTLCs.
+///
+/// At a high level, an HTLC being forwarded from one Lightning node to another Lightning node goes
+/// through the following states in the state machine:
+/// - Announced for addition by the originating node through the update_add_htlc message.
+/// - Added to the commitment transaction of the receiving node and originating node in turn
+///   through the exchange of commitment_signed and revoke_and_ack messages.
+/// - Announced for resolution (fulfillment or failure) by the receiving node through either one of
+///   the update_fulfill_htlc, update_fail_htlc, and update_fail_malformed_htlc messages.
+/// - Removed from the commitment transaction of the originating node and receiving node in turn
+///   through the exchange of commitment_signed and revoke_and_ack messages.
+///
+/// This can be used to inspect what next message an HTLC is waiting for to advance its state.
+#[derive(Clone, Debug, PartialEq)]
+pub enum OutboundHTLCStateDetails {
+       /// We are awaiting the appropriate revoke_and_ack's from the remote before the HTLC is added
+       /// on the remote's commitment transaction after update_add_htlc.
+       AwaitingRemoteRevokeToAdd,
+       /// The HTLC has been added to the remote's commitment transaction by sending commitment_signed
+       /// and receiving revoke_and_ack in return.
+       ///
+       /// The HTLC will remain in this state until the remote node resolves the HTLC, or until we
+       /// unilaterally close the channel due to a timeout with an uncooperative remote node.
+       Committed,
+       /// The HTLC has been fulfilled successfully by the remote with a preimage in update_fulfill_htlc,
+       /// and we removed the HTLC from our commitment transaction by receiving commitment_signed and
+       /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
+       /// for the removal from its commitment transaction.
+       AwaitingRemoteRevokeToRemoveSuccess,
+       /// The HTLC has been failed by the remote with update_fail_htlc or update_fail_malformed_htlc,
+       /// and we removed the HTLC from our commitment transaction by receiving commitment_signed and
+       /// returning revoke_and_ack. We are awaiting the appropriate revoke_and_ack's from the remote
+       /// for the removal from its commitment transaction.
+       AwaitingRemoteRevokeToRemoveFailure,
+}
+
+impl From<&OutboundHTLCState> for OutboundHTLCStateDetails {
+       fn from(state: &OutboundHTLCState) -> OutboundHTLCStateDetails {
+               match state {
+                       OutboundHTLCState::LocalAnnounced(_) =>
+                               OutboundHTLCStateDetails::AwaitingRemoteRevokeToAdd,
+                       OutboundHTLCState::Committed =>
+                               OutboundHTLCStateDetails::Committed,
+                       // RemoteRemoved states are ignored as the state is transient and the remote has not committed to
+                       // the state yet.
+                       OutboundHTLCState::RemoteRemoved(_) =>
+                               OutboundHTLCStateDetails::Committed,
+                       OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) =>
+                               OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveSuccess,
+                       OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Failure(_)) =>
+                               OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFailure,
+                       OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) =>
+                               OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveSuccess,
+                       OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Failure(_)) =>
+                               OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFailure,
+               }
+       }
+}
+
+impl_writeable_tlv_based_enum_upgradable!(OutboundHTLCStateDetails,
+       (0, AwaitingRemoteRevokeToAdd) => {},
+       (2, Committed) => {},
+       (4, AwaitingRemoteRevokeToRemoveSuccess) => {},
+       (6, AwaitingRemoteRevokeToRemoveFailure) => {};
+);
+
 #[derive(Clone)]
 #[cfg_attr(test, derive(Debug, PartialEq))]
 enum OutboundHTLCOutcome {
@@ -237,6 +416,58 @@ struct OutboundHTLCOutput {
        skimmed_fee_msat: Option<u64>,
 }
 
+/// Exposes details around pending outbound HTLCs.
+#[derive(Clone, Debug, PartialEq)]
+pub struct OutboundHTLCDetails {
+       /// The HTLC ID.
+       /// The IDs are incremented by 1 starting from 0 for each offered HTLC.
+       /// They are unique per channel and inbound/outbound direction, unless an HTLC was only announced
+       /// and not part of any commitment transaction.
+       ///
+       /// Not present when we are awaiting a remote revocation and the HTLC is not added yet.
+       pub htlc_id: Option<u64>,
+       /// The amount in msat.
+       pub amount_msat: u64,
+       /// The block height at which this HTLC expires.
+       pub cltv_expiry: u32,
+       /// The payment hash.
+       pub payment_hash: PaymentHash,
+       /// The state of the HTLC in the state machine.
+       ///
+       /// Determines on which commitment transactions the HTLC is included and what message the HTLC is
+       /// waiting for to advance to the next state.
+       ///
+       /// See [`OutboundHTLCStateDetails`] for information on the specific states.
+       ///
+       /// LDK will always fill this field in, but when downgrading to prior versions of LDK, new
+       /// states may result in `None` here.
+       pub state: Option<OutboundHTLCStateDetails>,
+       /// The extra fee being skimmed off the top of this HTLC.
+       pub skimmed_fee_msat: Option<u64>,
+       /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
+       /// from the local commitment transaction and added to the commitment transaction fee.
+       /// For non-anchor channels, this takes into account the cost of the second-stage HTLC
+       /// transactions as well.
+       ///
+       /// When the local commitment transaction is broadcasted as part of a unilateral closure,
+       /// the value of this HTLC will therefore not be claimable but instead burned as a transaction
+       /// fee.
+       ///
+       /// Note that dust limits are specific to each party. An HTLC can be dust for the local
+       /// commitment transaction but not for the counterparty's commitment transaction and vice versa.
+       pub is_dust: bool,
+}
+
+impl_writeable_tlv_based!(OutboundHTLCDetails, {
+       (0, htlc_id, required),
+       (2, amount_msat, required),
+       (4, cltv_expiry, required),
+       (6, payment_hash, required),
+       (7, state, upgradable_option),
+       (8, skimmed_fee_msat, required),
+       (10, is_dust, required),
+});
+
 /// See AwaitingRemoteRevoke ChannelState for more info
 #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
 enum HTLCUpdateAwaitingACK {
@@ -841,7 +1072,7 @@ pub(super) struct ReestablishResponses {
 pub(crate) struct ShutdownResult {
        pub(crate) closure_reason: ClosureReason,
        /// A channel monitor update to apply.
-       pub(crate) monitor_update: Option<(PublicKey, OutPoint, ChannelMonitorUpdate)>,
+       pub(crate) monitor_update: Option<(PublicKey, OutPoint, ChannelId, ChannelMonitorUpdate)>,
        /// A list of dropped outbound HTLCs that can safely be failed backwards immediately.
        pub(crate) dropped_outbound_htlcs: Vec<(HTLCSource, PaymentHash, PublicKey, ChannelId)>,
        /// An unbroadcasted batch funding transaction id. The closure of this channel should be
@@ -852,6 +1083,7 @@ pub(crate) struct ShutdownResult {
        pub(crate) channel_capacity_satoshis: u64,
        pub(crate) counterparty_node_id: PublicKey,
        pub(crate) unbroadcasted_funding_tx: Option<Transaction>,
+       pub(crate) channel_funding_txo: Option<OutPoint>,
 }
 
 /// If the majority of the channels funds are to the fundee and the initiator holds only just
@@ -1255,6 +1487,9 @@ pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
        // We track whether we already emitted a `ChannelReady` event.
        channel_ready_event_emitted: bool,
 
+       /// Some if we initiated to shut down the channel.
+       local_initiated_shutdown: Option<()>,
+
        /// The unique identifier used to re-derive the private key material for the channel through
        /// [`SignerProvider::derive_channel_signer`].
        channel_keys_id: [u8; 32],
@@ -1990,6 +2225,99 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                stats
        }
 
+       /// Returns information on all pending inbound HTLCs.
+       pub fn get_pending_inbound_htlc_details(&self) -> Vec<InboundHTLCDetails> {
+               let mut holding_cell_states = new_hash_map();
+               for holding_cell_update in self.holding_cell_htlc_updates.iter() {
+                       match holding_cell_update {
+                               HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
+                                       holding_cell_states.insert(
+                                               htlc_id,
+                                               InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFulfill,
+                                       );
+                               },
+                               HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
+                                       holding_cell_states.insert(
+                                               htlc_id,
+                                               InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail,
+                                       );
+                               },
+                               HTLCUpdateAwaitingACK::FailMalformedHTLC { htlc_id, .. } => {
+                                       holding_cell_states.insert(
+                                               htlc_id,
+                                               InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail,
+                                       );
+                               },
+                               // Outbound HTLC.
+                               HTLCUpdateAwaitingACK::AddHTLC { .. } => {},
+                       }
+               }
+               let mut inbound_details = Vec::new();
+               let htlc_success_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                       0
+               } else {
+                       let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
+                       dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
+               };
+               let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
+               for htlc in self.pending_inbound_htlcs.iter() {
+                       if let Some(state_details) = (&htlc.state).into() {
+                               inbound_details.push(InboundHTLCDetails{
+                                       htlc_id: htlc.htlc_id,
+                                       amount_msat: htlc.amount_msat,
+                                       cltv_expiry: htlc.cltv_expiry,
+                                       payment_hash: htlc.payment_hash,
+                                       state: Some(holding_cell_states.remove(&htlc.htlc_id).unwrap_or(state_details)),
+                                       is_dust: htlc.amount_msat / 1000 < holder_dust_limit_success_sat,
+                               });
+                       }
+               }
+               inbound_details
+       }
+
+       /// Returns information on all pending outbound HTLCs.
+       pub fn get_pending_outbound_htlc_details(&self) -> Vec<OutboundHTLCDetails> {
+               let mut outbound_details = Vec::new();
+               let htlc_timeout_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
+                       0
+               } else {
+                       let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
+                       dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
+               };
+               let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
+               for htlc in self.pending_outbound_htlcs.iter() {
+                       outbound_details.push(OutboundHTLCDetails{
+                               htlc_id: Some(htlc.htlc_id),
+                               amount_msat: htlc.amount_msat,
+                               cltv_expiry: htlc.cltv_expiry,
+                               payment_hash: htlc.payment_hash,
+                               skimmed_fee_msat: htlc.skimmed_fee_msat,
+                               state: Some((&htlc.state).into()),
+                               is_dust: htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat,
+                       });
+               }
+               for holding_cell_update in self.holding_cell_htlc_updates.iter() {
+                       if let HTLCUpdateAwaitingACK::AddHTLC {
+                               amount_msat,
+                               cltv_expiry,
+                               payment_hash,
+                               skimmed_fee_msat,
+                               ..
+                       } = *holding_cell_update {
+                               outbound_details.push(OutboundHTLCDetails{
+                                       htlc_id: None,
+                                       amount_msat: amount_msat,
+                                       cltv_expiry: cltv_expiry,
+                                       payment_hash: payment_hash,
+                                       skimmed_fee_msat: skimmed_fee_msat,
+                                       state: Some(OutboundHTLCStateDetails::AwaitingRemoteRevokeToAdd),
+                                       is_dust: amount_msat / 1000 < holder_dust_limit_timeout_sat,
+                               });
+                       }
+               }
+               outbound_details
+       }
+
        /// Get the available balances, see [`AvailableBalances`]'s fields for more info.
        /// Doesn't bother handling the
        /// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC
@@ -2414,10 +2742,11 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        // See test_duplicate_chan_id and test_pre_lockin_no_chan_closed_update for more.
                        if !self.channel_state.is_pre_funded_state() {
                                self.latest_monitor_update_id = CLOSED_CHANNEL_UPDATE_ID;
-                               Some((self.get_counterparty_node_id(), funding_txo, ChannelMonitorUpdate {
+                               Some((self.get_counterparty_node_id(), funding_txo, self.channel_id(), ChannelMonitorUpdate {
                                        update_id: self.latest_monitor_update_id,
                                        counterparty_node_id: Some(self.counterparty_node_id),
                                        updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
+                                       channel_id: Some(self.channel_id()),
                                }))
                        } else { None }
                } else { None };
@@ -2436,6 +2765,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                        channel_capacity_satoshis: self.channel_value_satoshis,
                        counterparty_node_id: self.counterparty_node_id,
                        unbroadcasted_funding_tx,
+                       channel_funding_txo: self.get_funding_txo(),
                }
        }
 
@@ -2796,6 +3126,7 @@ impl<SP: Deref> Channel<SP> where
                        updates: vec![ChannelMonitorUpdateStep::PaymentPreimage {
                                payment_preimage: payment_preimage_arg.clone(),
                        }],
+                       channel_id: Some(self.context.channel_id()),
                };
 
                if !self.context.channel_state.can_generate_new_commitment() {
@@ -3323,7 +3654,7 @@ impl<SP: Deref> Channel<SP> where
                Err(ChannelError::Close("Remote tried to fulfill/fail an HTLC we couldn't find".to_owned()))
        }
 
-       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(HTLCSource, u64), ChannelError> {
+       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(HTLCSource, u64, Option<u64>), ChannelError> {
                if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
                        return Err(ChannelError::Close("Got fulfill HTLC message when channel was not in an operational state".to_owned()));
                }
@@ -3331,7 +3662,7 @@ impl<SP: Deref> Channel<SP> where
                        return Err(ChannelError::Close("Peer sent update_fulfill_htlc when we needed a channel_reestablish".to_owned()));
                }
 
-               self.mark_outbound_htlc_removed(msg.htlc_id, Some(msg.payment_preimage), None).map(|htlc| (htlc.source.clone(), htlc.amount_msat))
+               self.mark_outbound_htlc_removed(msg.htlc_id, Some(msg.payment_preimage), None).map(|htlc| (htlc.source.clone(), htlc.amount_msat, htlc.skimmed_fee_msat))
        }
 
        pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> {
@@ -3534,7 +3865,8 @@ impl<SP: Deref> Channel<SP> where
                                htlc_outputs: htlcs_and_sigs,
                                claimed_htlcs,
                                nondust_htlc_sources,
-                       }]
+                       }],
+                       channel_id: Some(self.context.channel_id()),
                };
 
                self.context.cur_holder_commitment_transaction_number -= 1;
@@ -3610,6 +3942,7 @@ impl<SP: Deref> Channel<SP> where
                                update_id: self.context.latest_monitor_update_id + 1, // We don't increment this yet!
                                counterparty_node_id: Some(self.context.counterparty_node_id),
                                updates: Vec::new(),
+                               channel_id: Some(self.context.channel_id()),
                        };
 
                        let mut htlc_updates = Vec::new();
@@ -3788,6 +4121,7 @@ impl<SP: Deref> Channel<SP> where
                                idx: self.context.cur_counterparty_commitment_transaction_number + 1,
                                secret: msg.per_commitment_secret,
                        }],
+                       channel_id: Some(self.context.channel_id()),
                };
 
                // Update state now that we've passed all the can-fail calls...
@@ -4845,6 +5179,7 @@ impl<SP: Deref> Channel<SP> where
                                updates: vec![ChannelMonitorUpdateStep::ShutdownScript {
                                        scriptpubkey: self.get_closing_scriptpubkey(),
                                }],
+                               channel_id: Some(self.context.channel_id()),
                        };
                        self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
                        self.push_ret_blockable_mon_update(monitor_update)
@@ -4951,11 +5286,17 @@ impl<SP: Deref> Channel<SP> where
                        }
                }
 
+               let closure_reason = if self.initiated_shutdown() {
+                       ClosureReason::LocallyInitiatedCooperativeClosure
+               } else {
+                       ClosureReason::CounterpartyInitiatedCooperativeClosure
+               };
+
                assert!(self.context.shutdown_scriptpubkey.is_some());
                if let Some((last_fee, sig)) = self.context.last_sent_closing_fee {
                        if last_fee == msg.fee_satoshis {
                                let shutdown_result = ShutdownResult {
-                                       closure_reason: ClosureReason::CooperativeClosure,
+                                       closure_reason,
                                        monitor_update: None,
                                        dropped_outbound_htlcs: Vec::new(),
                                        unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(),
@@ -4964,6 +5305,7 @@ impl<SP: Deref> Channel<SP> where
                                        channel_capacity_satoshis: self.context.channel_value_satoshis,
                                        counterparty_node_id: self.context.counterparty_node_id,
                                        unbroadcasted_funding_tx: self.context.unbroadcasted_funding(),
+                                       channel_funding_txo: self.context.get_funding_txo(),
                                };
                                let tx = self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &sig);
                                self.context.channel_state = ChannelState::ShutdownComplete;
@@ -4989,7 +5331,7 @@ impl<SP: Deref> Channel<SP> where
                                                        .map_err(|_| ChannelError::Close("External signer refused to sign closing transaction".to_owned()))?;
                                                let (signed_tx, shutdown_result) = if $new_fee == msg.fee_satoshis {
                                                        let shutdown_result = ShutdownResult {
-                                                               closure_reason: ClosureReason::CooperativeClosure,
+                                                               closure_reason,
                                                                monitor_update: None,
                                                                dropped_outbound_htlcs: Vec::new(),
                                                                unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(),
@@ -4998,6 +5340,7 @@ impl<SP: Deref> Channel<SP> where
                                                                channel_capacity_satoshis: self.context.channel_value_satoshis,
                                                                counterparty_node_id: self.context.counterparty_node_id,
                                                                unbroadcasted_funding_tx: self.context.unbroadcasted_funding(),
+                                                               channel_funding_txo: self.context.get_funding_txo(),
                                                        };
                                                        self.context.channel_state = ChannelState::ShutdownComplete;
                                                        self.context.update_time_counter += 1;
@@ -5253,6 +5596,11 @@ impl<SP: Deref> Channel<SP> where
                self.context.channel_state.is_local_shutdown_sent()
        }
 
+       /// Returns true if we initiated to shut down the channel.
+       pub fn initiated_shutdown(&self) -> bool {
+               self.context.local_initiated_shutdown.is_some()
+       }
+
        /// Returns true if this channel is fully shut down. True here implies that no further actions
        /// may/will be taken on this channel, and thus this object should be freed. Any future changes
        /// will be handled appropriately by the chain monitor.
@@ -5982,7 +6330,8 @@ impl<SP: Deref> Channel<SP> where
                                feerate_per_kw: Some(counterparty_commitment_tx.feerate_per_kw()),
                                to_broadcaster_value_sat: Some(counterparty_commitment_tx.to_broadcaster_value_sat()),
                                to_countersignatory_value_sat: Some(counterparty_commitment_tx.to_countersignatory_value_sat()),
-                       }]
+                       }],
+                       channel_id: Some(self.context.channel_id()),
                };
                self.context.channel_state.set_awaiting_remote_revoke();
                monitor_update
@@ -6166,6 +6515,7 @@ impl<SP: Deref> Channel<SP> where
                // From here on out, we may not fail!
                self.context.target_closing_feerate_sats_per_kw = target_feerate_sats_per_kw;
                self.context.channel_state.set_local_shutdown_sent();
+               self.context.local_initiated_shutdown = Some(());
                self.context.update_time_counter += 1;
 
                let monitor_update = if update_shutdown_script {
@@ -6176,6 +6526,7 @@ impl<SP: Deref> Channel<SP> where
                                updates: vec![ChannelMonitorUpdateStep::ShutdownScript {
                                        scriptpubkey: self.get_closing_scriptpubkey(),
                                }],
+                               channel_id: Some(self.context.channel_id()),
                        };
                        self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
                        self.push_ret_blockable_mon_update(monitor_update)
@@ -6419,12 +6770,13 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                                channel_ready_event_emitted: false,
 
                                #[cfg(any(test, fuzzing))]
-                               historical_inbound_htlc_fulfills: HashSet::new(),
+                               historical_inbound_htlc_fulfills: new_hash_set(),
 
                                channel_type,
                                channel_keys_id,
 
                                blocked_monitor_updates: Vec::new(),
+                               local_initiated_shutdown: None,
                        },
                        unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
                })
@@ -6492,7 +6844,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                // Now that we're past error-generating stuff, update our local state:
 
                self.context.channel_state = ChannelState::FundingNegotiated;
-               self.context.channel_id = funding_txo.to_channel_id();
+               self.context.channel_id = ChannelId::v1_from_funding_outpoint(funding_txo);
 
                // If the funding transaction is a coinbase transaction, we need to set the minimum depth to 100.
                // We can skip this if it is a zero-conf channel.
@@ -6831,7 +7183,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
                                                          &self.context.channel_transaction_parameters,
                                                          funding_redeemscript.clone(), self.context.channel_value_satoshis,
                                                          obscure_factor,
-                                                         holder_commitment_tx, best_block, self.context.counterparty_node_id);
+                                                         holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id());
                channel_monitor.provide_initial_counterparty_commitment_tx(
                        counterparty_initial_bitcoin_tx.txid, Vec::new(),
                        self.context.cur_counterparty_commitment_transaction_number,
@@ -7220,11 +7572,13 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                                channel_ready_event_emitted: false,
 
                                #[cfg(any(test, fuzzing))]
-                               historical_inbound_htlc_fulfills: HashSet::new(),
+                               historical_inbound_htlc_fulfills: new_hash_set(),
 
                                channel_type,
                                channel_keys_id,
 
+                               local_initiated_shutdown: None,
+
                                blocked_monitor_updates: Vec::new(),
                        },
                        unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
@@ -7373,7 +7727,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                // Now that we're past error-generating stuff, update our local state:
 
                self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
-               self.context.channel_id = funding_txo.to_channel_id();
+               self.context.channel_id = ChannelId::v1_from_funding_outpoint(funding_txo);
                self.context.cur_counterparty_commitment_transaction_number -= 1;
                self.context.cur_holder_commitment_transaction_number -= 1;
 
@@ -7391,7 +7745,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
                                                          &self.context.channel_transaction_parameters,
                                                          funding_redeemscript.clone(), self.context.channel_value_satoshis,
                                                          obscure_factor,
-                                                         holder_commitment_tx, best_block, self.context.counterparty_node_id);
+                                                         holder_commitment_tx, best_block, self.context.counterparty_node_id, self.context.channel_id());
                channel_monitor.provide_initial_counterparty_commitment_tx(
                        counterparty_initial_commitment_tx.trust().txid(), Vec::new(),
                        self.context.cur_counterparty_commitment_transaction_number + 1,
@@ -7799,6 +8153,7 @@ impl<SP: Deref> Writeable for Channel<SP> where SP::Target: SignerProvider {
                        (39, pending_outbound_blinding_points, optional_vec),
                        (41, holding_cell_blinding_points, optional_vec),
                        (43, malformed_htlcs, optional_vec), // Added in 0.0.119
+                       (45, self.context.local_initiated_shutdown, option), // Added in 0.0.122
                });
 
                Ok(())
@@ -8036,7 +8391,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                let channel_update_status = Readable::read(reader)?;
 
                #[cfg(any(test, fuzzing))]
-               let mut historical_inbound_htlc_fulfills = HashSet::new();
+               let mut historical_inbound_htlc_fulfills = new_hash_set();
                #[cfg(any(test, fuzzing))]
                {
                        let htlc_fulfills_len: u64 = Readable::read(reader)?;
@@ -8086,6 +8441,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
 
                let mut is_batch_funding: Option<()> = None;
 
+               let mut local_initiated_shutdown: Option<()> = None;
+
                let mut pending_outbound_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
                let mut holding_cell_blinding_points_opt: Option<Vec<Option<PublicKey>>> = None;
 
@@ -8120,6 +8477,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                        (39, pending_outbound_blinding_points_opt, optional_vec),
                        (41, holding_cell_blinding_points_opt, optional_vec),
                        (43, malformed_htlcs, optional_vec), // Added in 0.0.119
+                       (45, local_initiated_shutdown, option),
                });
 
                let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -8350,6 +8708,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
                                channel_type: channel_type.unwrap(),
                                channel_keys_id,
 
+                               local_initiated_shutdown,
+
                                blocked_monitor_updates: blocked_monitor_updates.unwrap(),
                        }
                })