X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=31989a011a971b5dc55f170eac5e3de9e99205b2;hb=refs%2Fheads%2F2024-02-fix-build;hp=949b88637e4a1f6f81100916b0d65ced0275b2b2;hpb=25ec63f70e7195ac4984ce27d99f0de425518e7b;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 949b8863..31989a01 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -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 { + fn from(state: &InboundHTLCState) -> Option { + 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, + /// 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, } +/// 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, + /// 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, + /// The extra fee being skimmed off the top of this HTLC. + pub skimmed_fee_msat: Option, + /// 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, + pub(crate) channel_funding_txo: Option, } /// 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 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 ChannelContext where SP::Target: SignerProvider { stats } + /// Returns information on all pending inbound HTLCs. + pub fn get_pending_inbound_htlc_details(&self) -> Vec { + 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 { + 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 ChannelContext 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 ChannelContext 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 Channel 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 Channel 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), 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 Channel 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 OutboundV1Channel 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 OutboundV1Channel 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 OutboundV1Channel 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 InboundV1Channel 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 InboundV1Channel 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 InboundV1Channel 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 Writeable for Channel 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>> = None; let mut holding_cell_blinding_points_opt: Option>> = 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(), } })