+
+ let mut to_forward_infos = Vec::new();
+ let mut revoked_htlcs = Vec::new();
+ let mut update_fail_htlcs = Vec::new();
+ let mut update_fail_malformed_htlcs = Vec::new();
+ let mut require_commitment = false;
+ let mut value_to_self_msat_diff: i64 = 0;
+ // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
+ self.pending_inbound_htlcs.retain(|htlc| {
+ if htlc.state == InboundHTLCState::LocalRemoved {
+ if htlc.local_removed_fulfilled {
+ value_to_self_msat_diff += htlc.amount_msat as i64;
+ }
+ false
+ } else { true }
+ });
+ self.pending_outbound_htlcs.retain(|htlc| {
+ if htlc.state == OutboundHTLCState::AwaitingRemovedRemoteRevoke {
+ if let Some(reason) = htlc.fail_reason.clone() { // We really want take() here, but, again, non-mut ref :(
+ revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
+ } else {
+ // They fulfilled, so we sent them money
+ value_to_self_msat_diff -= htlc.amount_msat as i64;
+ }
+ false
+ } else { true }
+ });
+ for htlc in self.pending_inbound_htlcs.iter_mut() {
+ if htlc.state == InboundHTLCState::AwaitingRemoteRevokeToAnnounce {
+ htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke;
+ require_commitment = true;
+ } else if htlc.state == InboundHTLCState::AwaitingAnnouncedRemoteRevoke {
+ match htlc.pending_forward_state.take().unwrap() {
+ PendingHTLCStatus::Fail(fail_msg) => {
+ htlc.state = InboundHTLCState::LocalRemoved;
+ require_commitment = true;
+ match fail_msg {
+ HTLCFailureMsg::Relay(msg) => update_fail_htlcs.push(msg),
+ HTLCFailureMsg::Malformed(msg) => update_fail_malformed_htlcs.push(msg),
+ }
+ },
+ PendingHTLCStatus::Forward(forward_info) => {
+ to_forward_infos.push((forward_info, htlc.htlc_id));
+ htlc.state = InboundHTLCState::Committed;
+ }
+ }
+ }
+ }
+ for htlc in self.pending_outbound_htlcs.iter_mut() {
+ if htlc.state == OutboundHTLCState::LocalAnnounced {
+ htlc.state = OutboundHTLCState::Committed;
+ } else if htlc.state == OutboundHTLCState::AwaitingRemoteRevokeToRemove {
+ htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke;
+ require_commitment = true;
+ }
+ }
+ self.value_to_self_msat = (self.value_to_self_msat as i64 + value_to_self_msat_diff) as u64;
+
+ match self.free_holding_cell_htlcs()? {
+ Some(mut commitment_update) => {
+ commitment_update.0.update_fail_htlcs.reserve(update_fail_htlcs.len());
+ for fail_msg in update_fail_htlcs.drain(..) {
+ commitment_update.0.update_fail_htlcs.push(fail_msg);
+ }
+ commitment_update.0.update_fail_malformed_htlcs.reserve(update_fail_malformed_htlcs.len());
+ for fail_msg in update_fail_malformed_htlcs.drain(..) {
+ commitment_update.0.update_fail_malformed_htlcs.push(fail_msg);
+ }
+ Ok((Some(commitment_update.0), to_forward_infos, revoked_htlcs, commitment_update.1))
+ },
+ None => {
+ if require_commitment {
+ let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?;
+ Ok((Some(msgs::CommitmentUpdate {
+ update_add_htlcs: Vec::new(),
+ update_fulfill_htlcs: Vec::new(),
+ update_fail_htlcs,
+ update_fail_malformed_htlcs,
+ commitment_signed
+ }), to_forward_infos, revoked_htlcs, monitor_update))
+ } else {
+ Ok((None, to_forward_infos, revoked_htlcs, self.channel_monitor.clone()))
+ }
+ }
+ }
+ }
+
+ /// Removes any uncommitted HTLCs, to be used on peer disconnection, including any pending
+ /// HTLCs that we intended to add but haven't as we were waiting on a remote revoke.
+ /// Returns the set of PendingHTLCStatuses from remote uncommitted HTLCs (which we're
+ /// implicitly dropping) and the payment_hashes of HTLCs we tried to add but are dropping.
+ /// No further message handling calls may be made until a channel_reestablish dance has
+ /// completed.
+ pub fn remove_uncommitted_htlcs_and_mark_paused(&mut self) -> Vec<(HTLCSource, [u8; 32])> {
+ let mut outbound_drops = Vec::new();
+
+ assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
+ if self.channel_state < ChannelState::FundingSent as u32 {
+ self.channel_state = ChannelState::ShutdownComplete as u32;
+ return outbound_drops;
+ }
+
+ let mut inbound_drop_count = 0;
+ self.pending_inbound_htlcs.retain(|htlc| {
+ match htlc.state {
+ InboundHTLCState::RemoteAnnounced => {
+ // They sent us an update_add_htlc but we never got the commitment_signed.
+ // We'll tell them what commitment_signed we're expecting next and they'll drop
+ // this HTLC accordingly
+ inbound_drop_count += 1;
+ false
+ },
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => {
+ // Same goes for AwaitingRemoteRevokeToRemove and AwaitingRemovedRemoteRevoke
+ // We received a commitment_signed updating this HTLC and (at least hopefully)
+ // sent a revoke_and_ack (which we can re-transmit) and have heard nothing
+ // in response to it yet, so don't touch it.
+ true
+ },
+ InboundHTLCState::Committed => true,
+ InboundHTLCState::LocalRemoved => { // Same goes for LocalAnnounced
+ // We (hopefully) sent a commitment_signed updating this HTLC (which we can
+ // re-transmit if needed) and they may have even sent a revoke_and_ack back
+ // (that we missed). Keep this around for now and if they tell us they missed
+ // the commitment_signed we can re-transmit the update then.
+ true
+ },
+ }
+ });
+
+ for htlc in self.pending_outbound_htlcs.iter_mut() {
+ if htlc.state == OutboundHTLCState::RemoteRemoved {
+ // They sent us an update to remove this but haven't yet sent the corresponding
+ // commitment_signed, we need to move it back to Committed and they can re-send
+ // the update upon reconnection.
+ htlc.state = OutboundHTLCState::Committed;