X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=ce15eb2743787d0236fa03537e072f3559898e31;hb=55da9c434eeb6f108463e1c8d78914c759f43999;hp=33de30a4b84da724c57dafc610eb8418fd757572;hpb=3f416bc24e0e804e0cae1c8c5650b19500122b6d;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 33de30a4..ce15eb27 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -48,6 +48,7 @@ use crate::util::scid_utils::scid_from_parts; use crate::io; use crate::prelude::*; use core::{cmp,mem,fmt}; +use core::convert::TryInto; use core::ops::Deref; #[cfg(any(test, fuzzing, debug_assertions))] use crate::sync::Mutex; @@ -543,18 +544,17 @@ pub(super) struct ReestablishResponses { pub shutdown_msg: Option, } -/// The return type of `force_shutdown` -/// -/// Contains a tuple with the following: -/// - An optional (counterparty_node_id, funding_txo, [`ChannelMonitorUpdate`]) tuple -/// - A list of HTLCs to fail back in the form of the (source, payment hash, and this channel's -/// counterparty_node_id and channel_id). -/// - An optional transaction id identifying a corresponding batch funding transaction. -pub(crate) type ShutdownResult = ( - Option<(PublicKey, OutPoint, ChannelMonitorUpdate)>, - Vec<(HTLCSource, PaymentHash, PublicKey, ChannelId)>, - Option -); +/// The result of a shutdown that should be handled. +#[must_use] +pub(crate) struct ShutdownResult { + /// A channel monitor update to apply. + pub(crate) monitor_update: Option<(PublicKey, OutPoint, 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 + /// propagated to the remainder of the batch. + pub(crate) unbroadcasted_batch_funding_txid: Option, +} /// If the majority of the channels funds are to the fundee and the initiator holds only just /// enough funds to cover their reserve value, channels are at risk of getting "stuck". Because the @@ -1169,8 +1169,8 @@ impl ChannelContext where SP::Target: SignerProvider { match self.config.options.max_dust_htlc_exposure { MaxDustHTLCExposure::FeeRateMultiplier(multiplier) => { let feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight( - ConfirmationTarget::OnChainSweep); - feerate_per_kw as u64 * multiplier + ConfirmationTarget::OnChainSweep) as u64; + feerate_per_kw.saturating_mul(multiplier) }, MaxDustHTLCExposure::FixedLimitMsat(limit) => limit, } @@ -1754,14 +1754,14 @@ impl ChannelContext where SP::Target: SignerProvider { context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(context.get_channel_type()) / 1000) }; let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat; - if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat as i64 { + if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) { remaining_msat_below_dust_exposure_limit = Some(max_dust_htlc_exposure_msat.saturating_sub(on_counterparty_dust_htlc_exposure_msat)); dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000); } let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat; - if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat as i64 { + if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > max_dust_htlc_exposure_msat.try_into().unwrap_or(i64::max_value()) { remaining_msat_below_dust_exposure_limit = Some(cmp::min( remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()), max_dust_htlc_exposure_msat.saturating_sub(on_holder_dust_htlc_exposure_msat))); @@ -2074,7 +2074,11 @@ impl ChannelContext where SP::Target: SignerProvider { self.channel_state = ChannelState::ShutdownComplete as u32; self.update_time_counter += 1; - (monitor_update, dropped_outbound_htlcs, unbroadcasted_batch_funding_txid) + ShutdownResult { + monitor_update, + dropped_outbound_htlcs, + unbroadcasted_batch_funding_txid, + } } } @@ -4234,18 +4238,18 @@ impl Channel where pub fn maybe_propose_closing_signed( &mut self, fee_estimator: &LowerBoundedFeeEstimator, logger: &L) - -> Result<(Option, Option), ChannelError> + -> Result<(Option, Option, Option), ChannelError> where F::Target: FeeEstimator, L::Target: Logger { if self.context.last_sent_closing_fee.is_some() || !self.closing_negotiation_ready() { - return Ok((None, None)); + return Ok((None, None, None)); } if !self.context.is_outbound() { if let Some(msg) = &self.context.pending_counterparty_closing_signed.take() { return self.closing_signed(fee_estimator, &msg); } - return Ok((None, None)); + return Ok((None, None, None)); } let (our_min_fee, our_max_fee) = self.calculate_closing_fee_limits(fee_estimator); @@ -4270,7 +4274,7 @@ impl Channel where min_fee_satoshis: our_min_fee, max_fee_satoshis: our_max_fee, }), - }), None)) + }), None, None)) } } } @@ -4419,7 +4423,7 @@ impl Channel where pub fn closing_signed( &mut self, fee_estimator: &LowerBoundedFeeEstimator, msg: &msgs::ClosingSigned) - -> Result<(Option, Option), ChannelError> + -> Result<(Option, Option, Option), ChannelError> where F::Target: FeeEstimator { if self.context.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK { @@ -4441,7 +4445,7 @@ impl Channel where if self.context.channel_state & ChannelState::MonitorUpdateInProgress as u32 != 0 { self.context.pending_counterparty_closing_signed = Some(msg.clone()); - return Ok((None, None)); + return Ok((None, None, None)); } let funding_redeemscript = self.context.get_funding_redeemscript(); @@ -4471,10 +4475,15 @@ impl Channel where 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 { + monitor_update: None, + dropped_outbound_htlcs: Vec::new(), + unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(), + }; let tx = self.build_signed_closing_transaction(&mut closing_tx, &msg.signature, &sig); self.context.channel_state = ChannelState::ShutdownComplete as u32; self.context.update_time_counter += 1; - return Ok((None, Some(tx))); + return Ok((None, Some(tx), Some(shutdown_result))); } } @@ -4493,13 +4502,19 @@ impl Channel where let sig = ecdsa .sign_closing_transaction(&closing_tx, &self.context.secp_ctx) .map_err(|_| ChannelError::Close("External signer refused to sign closing transaction".to_owned()))?; - - let signed_tx = if $new_fee == msg.fee_satoshis { + let (signed_tx, shutdown_result) = if $new_fee == msg.fee_satoshis { + let shutdown_result = ShutdownResult { + monitor_update: None, + dropped_outbound_htlcs: Vec::new(), + unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(), + }; self.context.channel_state = ChannelState::ShutdownComplete as u32; self.context.update_time_counter += 1; let tx = self.build_signed_closing_transaction(&closing_tx, &msg.signature, &sig); - Some(tx) - } else { None }; + (Some(tx), Some(shutdown_result)) + } else { + (None, None) + }; self.context.last_sent_closing_fee = Some((used_fee, sig.clone())); Ok((Some(msgs::ClosingSigned { @@ -4510,7 +4525,7 @@ impl Channel where min_fee_satoshis: our_min_fee, max_fee_satoshis: our_max_fee, }), - }), signed_tx)) + }), signed_tx, shutdown_result)) } } } @@ -5588,7 +5603,7 @@ impl Channel where /// [`ChannelMonitorUpdate`] will be returned). pub fn get_shutdown(&mut self, signer_provider: &SP, their_features: &InitFeatures, target_feerate_sats_per_kw: Option, override_shutdown_script: Option) - -> Result<(msgs::Shutdown, Option, Vec<(HTLCSource, PaymentHash)>), APIError> + -> Result<(msgs::Shutdown, Option, Vec<(HTLCSource, PaymentHash)>, Option), APIError> { for htlc in self.context.pending_outbound_htlcs.iter() { if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { @@ -5643,11 +5658,18 @@ impl Channel where // From here on out, we may not fail! self.context.target_closing_feerate_sats_per_kw = target_feerate_sats_per_kw; - if self.context.channel_state & !STATE_FLAGS < ChannelState::FundingSent as u32 { + let shutdown_result = if self.context.channel_state & !STATE_FLAGS < ChannelState::FundingSent as u32 { + let shutdown_result = ShutdownResult { + monitor_update: None, + dropped_outbound_htlcs: Vec::new(), + unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(), + }; self.context.channel_state = ChannelState::ShutdownComplete as u32; + Some(shutdown_result) } else { self.context.channel_state |= ChannelState::LocalShutdownSent as u32; - } + None + }; self.context.update_time_counter += 1; let monitor_update = if update_shutdown_script { @@ -5683,7 +5705,7 @@ impl Channel where debug_assert!(!self.is_shutdown() || monitor_update.is_none(), "we can't both complete shutdown and return a monitor update"); - Ok((shutdown, monitor_update, dropped_outbound_htlcs)) + Ok((shutdown, monitor_update, dropped_outbound_htlcs, shutdown_result)) } pub fn inflight_htlc_sources(&self) -> impl Iterator {