- let mut htlc_updates = Vec::new();
- mem::swap(&mut htlc_updates, &mut self.context.holding_cell_htlc_updates);
- let mut update_add_htlcs = Vec::with_capacity(htlc_updates.len());
- let mut update_fulfill_htlcs = Vec::with_capacity(htlc_updates.len());
- let mut update_fail_htlcs = Vec::with_capacity(htlc_updates.len());
- let mut htlcs_to_fail = Vec::new();
- for htlc_update in htlc_updates.drain(..) {
- // Note that this *can* fail, though it should be due to rather-rare conditions on
- // fee races with adding too many outputs which push our total payments just over
- // the limit. In case it's less rare than I anticipate, we may want to revisit
- // handling this case better and maybe fulfilling some of the HTLCs while attempting
- // to rebalance channels.
- match &htlc_update {
- &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => {
- match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), false, logger) {
- Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
- Err(e) => {
- match e {
- ChannelError::Ignore(ref msg) => {
- log_info!(logger, "Failed to send HTLC with payment_hash {} due to {} in channel {}",
- log_bytes!(payment_hash.0), msg, log_bytes!(self.context.channel_id()));
- // If we fail to send here, then this HTLC should
- // be failed backwards. Failing to send here
- // indicates that this HTLC may keep being put back
- // into the holding cell without ever being
- // successfully forwarded/failed/fulfilled, causing
- // our counterparty to eventually close on us.
- htlcs_to_fail.push((source.clone(), *payment_hash));
- },
- _ => {
- panic!("Got a non-IgnoreError action trying to send holding cell HTLC");
- },
- }
- }
- }
- },
- &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, htlc_id, .. } => {
- // If an HTLC claim was previously added to the holding cell (via
- // `get_update_fulfill_htlc`, then generating the claim message itself must
- // not fail - any in between attempts to claim the HTLC will have resulted
- // in it hitting the holding cell again and we cannot change the state of a
- // holding cell HTLC from fulfill to anything else.
- let (update_fulfill_msg_option, mut additional_monitor_update) =
- if let UpdateFulfillFetch::NewClaim { msg, monitor_update, .. } = self.get_update_fulfill_htlc(htlc_id, *payment_preimage, logger) {
- (msg, monitor_update)
- } else { unreachable!() };
- update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap());
- monitor_update.updates.append(&mut additional_monitor_update.updates);
- },
- &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, ref err_packet } => {
- match self.fail_htlc(htlc_id, err_packet.clone(), false, logger) {
- Ok(update_fail_msg_option) => {
- // If an HTLC failure was previously added to the holding cell (via
- // `queue_fail_htlc`) then generating the fail message itself must
- // not fail - we should never end up in a state where we double-fail
- // an HTLC or fail-then-claim an HTLC as it indicates we didn't wait
- // for a full revocation before failing.
- update_fail_htlcs.push(update_fail_msg_option.unwrap())
- },
- Err(e) => {
- if let ChannelError::Ignore(_) = e {}
- else {
- panic!("Got a non-IgnoreError action trying to fail holding cell HTLC");
- }
- }
- }
- },
- }
- }
- if update_add_htlcs.is_empty() && update_fulfill_htlcs.is_empty() && update_fail_htlcs.is_empty() && self.context.holding_cell_update_fee.is_none() {
- return (None, htlcs_to_fail);
- }
- let update_fee = if let Some(feerate) = self.context.holding_cell_update_fee.take() {
- self.send_update_fee(feerate, false, logger)
- } else {
- None
- };
-
- let mut additional_update = self.build_commitment_no_status_check(logger);
- // build_commitment_no_status_check and get_update_fulfill_htlc may bump latest_monitor_id
- // but we want them to be strictly increasing by one, so reset it here.
- self.context.latest_monitor_update_id = monitor_update.update_id;
- monitor_update.updates.append(&mut additional_update.updates);
-
- log_debug!(logger, "Freeing holding cell in channel {} resulted in {}{} HTLCs added, {} HTLCs fulfilled, and {} HTLCs failed.",
- log_bytes!(self.context.channel_id()), if update_fee.is_some() { "a fee update, " } else { "" },
- update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len());
-
- self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());
- (self.push_ret_blockable_mon_update(monitor_update), htlcs_to_fail)
- } else {
- (None, Vec::new())
- }
- }
-
- /// Handles receiving a remote's revoke_and_ack. Note that we may return a new
- /// commitment_signed message here in case we had pending outbound HTLCs to add which were
- /// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail,
- /// generating an appropriate error *after* the channel state has been updated based on the
- /// revoke_and_ack message.
- pub fn revoke_and_ack<L: Deref>(&mut self, msg: &msgs::RevokeAndACK, logger: &L) -> Result<(Vec<(HTLCSource, PaymentHash)>, Option<&ChannelMonitorUpdate>), ChannelError>
- where L::Target: Logger,
- {
- if (self.context.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) {
- return Err(ChannelError::Close("Got revoke/ACK message when channel was not in an operational state".to_owned()));
- }
- if self.context.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
- return Err(ChannelError::Close("Peer sent revoke_and_ack when we needed a channel_reestablish".to_owned()));
- }
- if self.context.channel_state & BOTH_SIDES_SHUTDOWN_MASK == BOTH_SIDES_SHUTDOWN_MASK && self.context.last_sent_closing_fee.is_some() {
- return Err(ChannelError::Close("Peer sent revoke_and_ack after we'd started exchanging closing_signeds".to_owned()));
- }
-
- let secret = secp_check!(SecretKey::from_slice(&msg.per_commitment_secret), "Peer provided an invalid per_commitment_secret".to_owned());
-
- if let Some(counterparty_prev_commitment_point) = self.context.counterparty_prev_commitment_point {
- if PublicKey::from_secret_key(&self.context.secp_ctx, &secret) != counterparty_prev_commitment_point {
- return Err(ChannelError::Close("Got a revoke commitment secret which didn't correspond to their current pubkey".to_owned()));
- }
- }
-
- if self.context.channel_state & ChannelState::AwaitingRemoteRevoke as u32 == 0 {
- // Our counterparty seems to have burned their coins to us (by revoking a state when we
- // haven't given them a new commitment transaction to broadcast). We should probably
- // take advantage of this by updating our channel monitor, sending them an error, and
- // waiting for them to broadcast their latest (now-revoked claim). But, that would be a
- // lot of work, and there's some chance this is all a misunderstanding anyway.
- // We have to do *something*, though, since our signer may get mad at us for otherwise
- // jumping a remote commitment number, so best to just force-close and move on.
- return Err(ChannelError::Close("Received an unexpected revoke_and_ack".to_owned()));
- }
-
- #[cfg(any(test, fuzzing))]
- {
- *self.context.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
- *self.context.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
- }
-
- self.context.holder_signer.validate_counterparty_revocation(
- self.context.cur_counterparty_commitment_transaction_number + 1,
- &secret
- ).map_err(|_| ChannelError::Close("Failed to validate revocation from peer".to_owned()))?;
-
- self.context.commitment_secrets.provide_secret(self.context.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
- .map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
- self.context.latest_monitor_update_id += 1;
- let mut monitor_update = ChannelMonitorUpdate {
- update_id: self.context.latest_monitor_update_id,
- updates: vec![ChannelMonitorUpdateStep::CommitmentSecret {
- idx: self.context.cur_counterparty_commitment_transaction_number + 1,
- secret: msg.per_commitment_secret,
- }],
- };
-
- // Update state now that we've passed all the can-fail calls...
- // (note that we may still fail to generate the new commitment_signed message, but that's
- // OK, we step the channel here and *then* if the new generation fails we can fail the
- // channel based on that, but stepping stuff here should be safe either way.
- self.context.channel_state &= !(ChannelState::AwaitingRemoteRevoke as u32);
- self.context.sent_message_awaiting_response = None;
- self.context.counterparty_prev_commitment_point = self.context.counterparty_cur_commitment_point;
- self.context.counterparty_cur_commitment_point = Some(msg.next_per_commitment_point);
- self.context.cur_counterparty_commitment_transaction_number -= 1;
-
- if self.context.announcement_sigs_state == AnnouncementSigsState::Committed {
- self.context.announcement_sigs_state = AnnouncementSigsState::PeerReceived;
- }
-
- log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", log_bytes!(self.context.channel_id()));
- let mut to_forward_infos = Vec::new();
- let mut revoked_htlcs = Vec::new();
- let mut finalized_claimed_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;
-
- {
- // Take references explicitly so that we can hold multiple references to self.context.
- let pending_inbound_htlcs: &mut Vec<_> = &mut self.context.pending_inbound_htlcs;
- let pending_outbound_htlcs: &mut Vec<_> = &mut self.context.pending_outbound_htlcs;
-
- // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug)
- pending_inbound_htlcs.retain(|htlc| {
- if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
- log_trace!(logger, " ...removing inbound LocalRemoved {}", log_bytes!(htlc.payment_hash.0));
- if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
- value_to_self_msat_diff += htlc.amount_msat as i64;
- }
- false
- } else { true }
- });
- pending_outbound_htlcs.retain(|htlc| {
- if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) = &htlc.state {
- log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", log_bytes!(htlc.payment_hash.0));
- if let OutboundHTLCOutcome::Failure(reason) = outcome.clone() { // We really want take() here, but, again, non-mut ref :(
- revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
- } else {
- finalized_claimed_htlcs.push(htlc.source.clone());
- // They fulfilled, so we sent them money
- value_to_self_msat_diff -= htlc.amount_msat as i64;
- }
- false
- } else { true }
- });
- for htlc in pending_inbound_htlcs.iter_mut() {
- let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state {
- true
- } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state {
- true
- } else { false };
- if swap {
- let mut state = InboundHTLCState::Committed;
- mem::swap(&mut state, &mut htlc.state);
-
- if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state {
- log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to AwaitingAnnouncedRemoteRevoke", log_bytes!(htlc.payment_hash.0));
- htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info);
- require_commitment = true;
- } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state {
- match forward_info {
- PendingHTLCStatus::Fail(fail_msg) => {
- log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to LocalRemoved due to PendingHTLCStatus indicating failure", log_bytes!(htlc.payment_hash.0));
- require_commitment = true;
- match fail_msg {
- HTLCFailureMsg::Relay(msg) => {
- htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone()));
- update_fail_htlcs.push(msg)
- },
- HTLCFailureMsg::Malformed(msg) => {
- htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code)));
- update_fail_malformed_htlcs.push(msg)
- },
- }
- },
- PendingHTLCStatus::Forward(forward_info) => {
- log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", log_bytes!(htlc.payment_hash.0));
- to_forward_infos.push((forward_info, htlc.htlc_id));
- htlc.state = InboundHTLCState::Committed;
- }