+ /// Calculates and returns our minimum and maximum closing transaction fee amounts, in whole
+ /// satoshis. The amounts remain consistent unless a peer disconnects/reconnects or we restart,
+ /// at which point they will be recalculated.
+ fn calculate_closing_fee_limits<F: Deref>(&mut self, fee_estimator: &F) -> (u64, u64)
+ where F::Target: FeeEstimator
+ {
+ if let Some((min, max)) = self.closing_fee_limits { return (min, max); }
+
+ // Propose a range from our current Background feerate to our Normal feerate plus our
+ // force_close_avoidance_max_fee_satoshis.
+ // If we fail to come to consensus, we'll have to force-close.
+ let mut proposed_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
+ let normal_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal);
+ let mut proposed_max_feerate = if self.is_outbound() { normal_feerate } else { u32::max_value() };
+
+ // The spec requires that (when the channel does not have anchors) we only send absolute
+ // channel fees no greater than the absolute channel fee on the current commitment
+ // transaction. It's unclear *which* commitment transaction this refers to, and there isn't
+ // very good reason to apply such a limit in any case. We don't bother doing so, risking
+ // some force-closure by old nodes, but we wanted to close the channel anyway.
+
+ if let Some(target_feerate) = self.target_closing_feerate_sats_per_kw {
+ let min_feerate = if self.is_outbound() { target_feerate } else { cmp::min(self.feerate_per_kw, target_feerate) };
+ proposed_feerate = cmp::max(proposed_feerate, min_feerate);
+ proposed_max_feerate = cmp::max(proposed_max_feerate, min_feerate);
+ }
+
+ // Note that technically we could end up with a lower minimum fee if one sides' balance is
+ // below our dust limit, causing the output to disappear. We don't bother handling this
+ // case, however, as this should only happen if a channel is closed before any (material)
+ // payments have been made on it. This may cause slight fee overpayment and/or failure to
+ // come to consensus with our counterparty on appropriate fees, however it should be a
+ // relatively rare case. We can revisit this later, though note that in order to determine
+ // if the funders' output is dust we have to know the absolute fee we're going to use.
+ let tx_weight = self.get_closing_transaction_weight(Some(&self.get_closing_scriptpubkey()), Some(self.counterparty_shutdown_scriptpubkey.as_ref().unwrap()));
+ let proposed_total_fee_satoshis = proposed_feerate as u64 * tx_weight / 1000;
+ let proposed_max_total_fee_satoshis = if self.is_outbound() {
+ // We always add force_close_avoidance_max_fee_satoshis to our normal
+ // feerate-calculated fee, but allow the max to be overridden if we're using a
+ // target feerate-calculated fee.
+ cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.force_close_avoidance_max_fee_satoshis,
+ proposed_max_feerate as u64 * tx_weight / 1000)
+ } else {
+ self.channel_value_satoshis - (self.value_to_self_msat + 999) / 1000
+ };
+
+ self.closing_fee_limits = Some((proposed_total_fee_satoshis, proposed_max_total_fee_satoshis));
+ self.closing_fee_limits.clone().unwrap()
+ }
+
+ /// Returns true if we're ready to commence the closing_signed negotiation phase. This is true
+ /// after both sides have exchanged a `shutdown` message and all HTLCs have been drained. At
+ /// 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.pending_inbound_htlcs.is_empty() && self.pending_outbound_htlcs.is_empty() &&
+ self.channel_state &
+ (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::AwaitingRemoteRevoke as u32 |
+ ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateFailed as u32)
+ == BOTH_SIDES_SHUTDOWN_MASK &&
+ self.pending_update_fee.is_none()
+ }
+
+ /// Checks if the closing_signed negotiation is making appropriate progress, possibly returning
+ /// an Err if no progress is being made and the channel should be force-closed instead.
+ /// Should be called on a one-minute timer.
+ pub fn timer_check_closing_negotiation_progress(&mut self) -> Result<(), ChannelError> {
+ if self.closing_negotiation_ready() {
+ if self.closing_signed_in_flight {
+ return Err(ChannelError::Close("closing_signed negotiation failed to finish within two timer ticks".to_owned()));
+ } else {
+ self.closing_signed_in_flight = true;
+ }
+ }
+ Ok(())
+ }
+