- let mut included_htlcs = 0;
- for ref htlc in self.pending_inbound_htlcs.iter() {
- if htlc.amount_msat / 1000 < real_dust_limit_success_sat {
- continue
- }
- // We include LocalRemoved HTLCs here because we may still need to broadcast a commitment
- // transaction including this HTLC if it times out before they RAA.
- included_htlcs += 1;
- }
-
- for ref htlc in self.pending_outbound_htlcs.iter() {
- if htlc.amount_msat / 1000 < real_dust_limit_timeout_sat {
- continue
- }
- match htlc.state {
- OutboundHTLCState::LocalAnnounced {..} => included_htlcs += 1,
- OutboundHTLCState::Committed => included_htlcs += 1,
- OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
- // We don't include AwaitingRemoteRevokeToRemove HTLCs because our next commitment
- // transaction won't be generated until they send us their next RAA, which will mean
- // dropping any HTLCs in this state.
- _ => {},
- }
- }
-
- for htlc in self.holding_cell_htlc_updates.iter() {
- match htlc {
- &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } => {
- if amount_msat / 1000 < real_dust_limit_timeout_sat {
- continue
- }
- included_htlcs += 1
- },
- _ => {}, // Don't include claims/fails that are awaiting ack, because once we get the
- // ack we're guaranteed to never include them in commitment txs anymore.
- }
- }
-
- let num_htlcs = included_htlcs + addl_htlcs;
- let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors());
- #[cfg(any(test, fuzzing))]
- {
- let mut fee = res;
- if fee_spike_buffer_htlc.is_some() {
- fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors());
- }
- let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
- + self.holding_cell_htlc_updates.len();
- let commitment_tx_info = CommitmentTxInfoCached {
- fee,
- total_pending_htlcs,
- next_holder_htlc_id: match htlc.origin {
- HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
- HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
- },
- next_counterparty_htlc_id: match htlc.origin {
- HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
- HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
- },
- feerate: self.feerate_per_kw,
- };
- *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
- }
- res
- }
-
- // Get the commitment tx fee for the remote's next commitment transaction based on the number of
- // pending HTLCs that are on track to be in their next commitment tx, plus an additional HTLC if
- // `fee_spike_buffer_htlc` is Some, plus a new HTLC given by `new_htlc_amount`. Dust HTLCs are
- // excluded.
- fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
- assert!(!self.is_outbound());
-
- let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() {
- (0, 0)
- } else {
- (self.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000,
- self.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000)
- };
- let real_dust_limit_success_sat = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis;
- let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis;
-
- let mut addl_htlcs = 0;
- if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
- match htlc.origin {
- HTLCInitiator::LocalOffered => {
- if htlc.amount_msat / 1000 >= real_dust_limit_success_sat {
- addl_htlcs += 1;
- }
- },
- HTLCInitiator::RemoteOffered => {
- if htlc.amount_msat / 1000 >= real_dust_limit_timeout_sat {
- addl_htlcs += 1;
- }
- }
- }
-
- // When calculating the set of HTLCs which will be included in their next commitment_signed, all
- // non-dust inbound HTLCs are included (as all states imply it will be included) and only
- // committed outbound HTLCs, see below.
- let mut included_htlcs = 0;
- for ref htlc in self.pending_inbound_htlcs.iter() {
- if htlc.amount_msat / 1000 <= real_dust_limit_timeout_sat {
- continue
- }
- included_htlcs += 1;
- }
-
- for ref htlc in self.pending_outbound_htlcs.iter() {
- if htlc.amount_msat / 1000 <= real_dust_limit_success_sat {
- continue
- }
- // We only include outbound HTLCs if it will not be included in their next commitment_signed,
- // i.e. if they've responded to us with an RAA after announcement.
- match htlc.state {
- OutboundHTLCState::Committed => included_htlcs += 1,
- OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
- OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1,
- _ => {},
- }
- }
-
- let num_htlcs = included_htlcs + addl_htlcs;
- let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors());
- #[cfg(any(test, fuzzing))]
- {
- let mut fee = res;
- if fee_spike_buffer_htlc.is_some() {
- fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors());
- }
- let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
- let commitment_tx_info = CommitmentTxInfoCached {
- fee,
- total_pending_htlcs,
- next_holder_htlc_id: match htlc.origin {
- HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
- HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
- },
- next_counterparty_htlc_id: match htlc.origin {
- HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
- HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
- },
- feerate: self.feerate_per_kw,
- };
- *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
- }
- res
- }
-
- pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
- where F: for<'a> Fn(&'a Self, PendingHTLCStatus, u16) -> PendingHTLCStatus, L::Target: Logger {
- // We can't accept HTLCs sent after we've sent a shutdown.
- let local_sent_shutdown = (self.channel_state & (ChannelState::ChannelReady as u32 | ChannelState::LocalShutdownSent as u32)) != (ChannelState::ChannelReady as u32);
- if local_sent_shutdown {
- pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x4000|8);
- }
- // If the remote has sent a shutdown prior to adding this HTLC, then they are in violation of the spec.
- let remote_sent_shutdown = (self.channel_state & (ChannelState::ChannelReady as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelReady as u32);
- if remote_sent_shutdown {
- return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state".to_owned()));
- }
- if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
- return Err(ChannelError::Close("Peer sent update_add_htlc when we needed a channel_reestablish".to_owned()));
- }
- if msg.amount_msat > self.channel_value_satoshis * 1000 {
- return Err(ChannelError::Close("Remote side tried to send more than the total value of the channel".to_owned()));
- }
- if msg.amount_msat == 0 {
- return Err(ChannelError::Close("Remote side tried to send a 0-msat HTLC".to_owned()));
- }
- if msg.amount_msat < self.holder_htlc_minimum_msat {
- return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.holder_htlc_minimum_msat, msg.amount_msat)));
- }
-
- let inbound_stats = self.get_inbound_pending_htlc_stats(None);
- let outbound_stats = self.get_outbound_pending_htlc_stats(None);
- if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 {
- return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
- }
- if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat {
- return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat)));
- }
- // Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet
- // the reserve_satoshis we told them to always have as direct payment so that they lose
- // something if we punish them for broadcasting an old state).
- // Note that we don't really care about having a small/no to_remote output in our local
- // commitment transactions, as the purpose of the channel reserve is to ensure we can
- // punish *them* if they misbehave, so we discount any outbound HTLCs which will not be
- // present in the next commitment transaction we send them (at least for fulfilled ones,
- // failed ones won't modify value_to_self).
- // Note that we will send HTLCs which another instance of rust-lightning would think
- // violate the reserve value if we do not do this (as we forget inbound HTLCs from the
- // Channel state once they will not be present in the next received commitment
- // transaction).
- let mut removed_outbound_total_msat = 0;
- for ref htlc in self.pending_outbound_htlcs.iter() {
- if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) = htlc.state {
- removed_outbound_total_msat += htlc.amount_msat;
- } else if let OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) = htlc.state {
- removed_outbound_total_msat += htlc.amount_msat;
- }
- }
-
- let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() {
- (0, 0)
- } else {
- let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
- (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000,
- dust_buffer_feerate * htlc_success_tx_weight(false) / 1000)
- };
- let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis;
- if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats {
- let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat;
- if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
- log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on counterparty commitment tx",
- on_counterparty_tx_dust_htlc_exposure_msat, self.get_max_dust_htlc_exposure_msat());
- pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
- }
- }
-
- let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
- if msg.amount_msat / 1000 < exposure_dust_limit_success_sats {
- let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat;
- if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() {
- log_info!(logger, "Cannot accept value that would put our exposure to dust HTLCs at {} over the limit {} on holder commitment tx",
- on_holder_tx_dust_htlc_exposure_msat, self.get_max_dust_htlc_exposure_msat());
- pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
- }
- }
-
- let pending_value_to_self_msat =
- self.value_to_self_msat + inbound_stats.pending_htlcs_value_msat - removed_outbound_total_msat;
- let pending_remote_value_msat =
- self.channel_value_satoshis * 1000 - pending_value_to_self_msat;
- if pending_remote_value_msat < msg.amount_msat {
- return Err(ChannelError::Close("Remote HTLC add would overdraw remaining funds".to_owned()));
- }
-
- // Check that the remote can afford to pay for this HTLC on-chain at the current
- // feerate_per_kw, while maintaining their channel reserve (as required by the spec).
- let remote_commit_tx_fee_msat = if self.is_outbound() { 0 } else {
- let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
- self.next_remote_commit_tx_fee_msat(htlc_candidate, None) // Don't include the extra fee spike buffer HTLC in calculations
- };
- if pending_remote_value_msat - msg.amount_msat < remote_commit_tx_fee_msat {
- return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
- };
-
- if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < self.holder_selected_channel_reserve_satoshis * 1000 {
- return Err(ChannelError::Close("Remote HTLC add would put them under remote reserve value".to_owned()));
- }
-
- if !self.is_outbound() {