Add message ordering return value to handling channel_reestablish
[rust-lightning] / src / ln / channel.rs
index db0b0475a4cd5712d18848ccf3b9a90e41f92252..c53cf2520d6c79a29e5d4144ebb5124e7776a99d 100644 (file)
@@ -14,7 +14,7 @@ use crypto::digest::Digest;
 use crypto::hkdf::{hkdf_extract,hkdf_expand};
 
 use ln::msgs;
-use ln::msgs::{ErrorAction, HandleError};
+use ln::msgs::{ErrorAction, HandleError, RAACommitmentOrder};
 use ln::channelmonitor::ChannelMonitor;
 use ln::channelmanager::{PendingHTLCStatus, HTLCSource, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg};
 use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
@@ -141,7 +141,6 @@ struct InboundHTLCOutput {
        state: InboundHTLCState,
 }
 
-#[derive(PartialEq)]
 enum OutboundHTLCState {
        /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
        /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -153,7 +152,9 @@ enum OutboundHTLCState {
        ///    allowed to remove it, the "can only be removed once committed on both sides" requirement
        ///    doesn't matter to us and its up to them to enforce it, worst-case they jump ahead but
        ///    we'll never get out of sync).
-       LocalAnnounced,
+       /// Note that we Box the OnionPacket as its rather large and we don't want to blow up
+       /// OutboundHTLCOutput's size just for a temporary bit
+       LocalAnnounced(Box<msgs::OnionPacket>),
        Committed,
        /// Remote removed this (outbound) HTLC. We're waiting on their commitment_signed to finalize
        /// the change (though they'll need to revoke before we fail the payment).
@@ -268,6 +269,7 @@ enum ChannelState {
        ShutdownComplete = 2048,
 }
 const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32);
+const MULTI_STATE_FLAGS: u32 = (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDisconnected as u32);
 
 const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
 
@@ -818,7 +820,7 @@ impl Channel {
 
                for ref htlc in self.pending_outbound_htlcs.iter() {
                        let include = match htlc.state {
-                               OutboundHTLCState::LocalAnnounced => generated_by_local,
+                               OutboundHTLCState::LocalAnnounced(_) => generated_by_local,
                                OutboundHTLCState::Committed => true,
                                OutboundHTLCState::RemoteRemoved => generated_by_local,
                                OutboundHTLCState::AwaitingRemoteRevokeToRemove => generated_by_local,
@@ -1543,7 +1545,7 @@ impl Channel {
                Ok(())
        }
 
-       /// Removes an outbound HTLC which has been commitment_signed by the remote end
+       /// Marks an outbound HTLC which we have received update_fail/fulfill/malformed
        #[inline]
        fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option<HTLCFailReason>) -> Result<&HTLCSource, ChannelError> {
                for htlc in self.pending_outbound_htlcs.iter_mut() {
@@ -1556,14 +1558,14 @@ impl Channel {
                                                }
                                };
                                match htlc.state {
-                                       OutboundHTLCState::LocalAnnounced =>
-                                               return Err(ChannelError::Close("Remote tried to fulfill HTLC before it had been committed")),
+                                       OutboundHTLCState::LocalAnnounced(_) =>
+                                               return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC before it had been committed")),
                                        OutboundHTLCState::Committed => {
                                                htlc.state = OutboundHTLCState::RemoteRemoved;
                                                htlc.fail_reason = fail_reason;
                                        },
                                        OutboundHTLCState::AwaitingRemoteRevokeToRemove | OutboundHTLCState::AwaitingRemovedRemoteRevoke | OutboundHTLCState::RemoteRemoved =>
-                                               return Err(ChannelError::Close("Remote tried to fulfill HTLC that they'd already fulfilled")),
+                                               return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC that they'd already fulfilled/failed")),
                                }
                                return Ok(&htlc.source);
                        }
@@ -1686,7 +1688,7 @@ impl Channel {
                        }
                }
                for htlc in self.pending_outbound_htlcs.iter_mut() {
-                       if htlc.state == OutboundHTLCState::RemoteRemoved {
+                       if let OutboundHTLCState::RemoteRemoved = htlc.state {
                                htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove;
                                need_our_commitment = true;
                        }
@@ -1846,7 +1848,7 @@ impl Channel {
                        } else { true }
                });
                self.pending_outbound_htlcs.retain(|htlc| {
-                       if htlc.state == OutboundHTLCState::AwaitingRemovedRemoteRevoke {
+                       if let OutboundHTLCState::AwaitingRemovedRemoteRevoke = htlc.state {
                                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 {
@@ -1893,9 +1895,9 @@ impl Channel {
                        }
                }
                for htlc in self.pending_outbound_htlcs.iter_mut() {
-                       if htlc.state == OutboundHTLCState::LocalAnnounced {
+                       if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
                                htlc.state = OutboundHTLCState::Committed;
-                       } else if htlc.state == OutboundHTLCState::AwaitingRemoteRevokeToRemove {
+                       } else if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state {
                                htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke;
                                require_commitment = true;
                        }
@@ -1958,10 +1960,12 @@ impl Channel {
                if !self.channel_outbound {
                        panic!("Cannot send fee from inbound channel");
                }
-
                if !self.is_usable() {
                        panic!("Cannot update fee until channel is fully established and we haven't started shutting down");
                }
+               if !self.is_live() {
+                       panic!("Cannot update fee while peer is disconnected (ChannelManager should have caught this)");
+               }
 
                if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
                        self.holding_cell_update_fee = Some(feerate_per_kw);
@@ -2030,7 +2034,7 @@ impl Channel {
                });
 
                for htlc in self.pending_outbound_htlcs.iter_mut() {
-                       if htlc.state == OutboundHTLCState::RemoteRemoved {
+                       if let OutboundHTLCState::RemoteRemoved = htlc.state {
                                // 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.
@@ -2068,7 +2072,7 @@ impl Channel {
 
        /// May panic if some calls other than message-handling calls (which will all Err immediately)
        /// have been called between remove_uncommitted_htlcs_and_mark_paused and this call.
-       pub fn channel_reestablish(&mut self, msg: &msgs::ChannelReestablish) -> Result<(Option<msgs::FundingLocked>, Option<msgs::RevokeAndACK>, Option<msgs::CommitmentUpdate>, Option<ChannelMonitor>), ChannelError> {
+       pub fn channel_reestablish(&mut self, msg: &msgs::ChannelReestablish) -> Result<(Option<msgs::FundingLocked>, Option<msgs::RevokeAndACK>, Option<msgs::CommitmentUpdate>, Option<ChannelMonitor>, RAACommitmentOrder), ChannelError> {
                if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 {
                        // While BOLT 2 doesn't indicate explicitly we should error this channel here, it
                        // almost certainly indicates we are going to end up out-of-sync in some way, so we
@@ -2078,40 +2082,51 @@ impl Channel {
 
                if msg.next_local_commitment_number == 0 || msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER ||
                                msg.next_remote_commitment_number == 0 || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER {
-                       return Err(ChannelError::Close("Peer send garbage channel_reestablish"));
+                       return Err(ChannelError::Close("Peer sent a garbage channel_reestablish"));
                }
 
                // Go ahead and unmark PeerDisconnected as various calls we may make check for it (and all
                // remaining cases either succeed or ErrorMessage-fail).
                self.channel_state &= !(ChannelState::PeerDisconnected as u32);
 
-               let mut required_revoke = None;
-               if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
+               let required_revoke = if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
                        // Remote isn't waiting on any RevokeAndACK from us!
                        // Note that if we need to repeat our FundingLocked we'll do that in the next if block.
+                       None
                } else if msg.next_remote_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number {
                        let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number));
                        let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 2);
-                       required_revoke = Some(msgs::RevokeAndACK {
+                       Some(msgs::RevokeAndACK {
                                channel_id: self.channel_id,
                                per_commitment_secret,
                                next_per_commitment_point,
-                       });
+                       })
                } else {
                        return Err(ChannelError::Close("Peer attempted to reestablish channel with a very old local commitment transaction"));
-               }
+               };
 
-               if msg.next_local_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number {
-                       if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number {
-                               log_debug!(self, "Reconnected channel {} with no lost commitment txn", log_bytes!(self.channel_id()));
-                               if msg.next_local_commitment_number == 1 && msg.next_remote_commitment_number == 1 {
-                                       let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
-                                       let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
-                                       return Ok((Some(msgs::FundingLocked {
-                                               channel_id: self.channel_id(),
-                                               next_per_commitment_point: next_per_commitment_point,
-                                       }), None, None, None));
-                               }
+               // We increment cur_remote_commitment_transaction_number only upon receipt of
+               // revoke_and_ack, not on sending commitment_signed, so we add one if have
+               // AwaitingRemoteRevoke set, which indicates we sent a commitment_signed but haven't gotten
+               // the corresponding revoke_and_ack back yet.
+               let our_next_remote_commitment_number = INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number + if (self.channel_state & ChannelState::AwaitingRemoteRevoke as u32) != 0 { 1 } else { 0 };
+
+               let resend_funding_locked = if msg.next_local_commitment_number == 1 && INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number == 1 {
+                       let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
+                       let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
+                       Some(msgs::FundingLocked {
+                               channel_id: self.channel_id(),
+                               next_per_commitment_point: next_per_commitment_point,
+                       })
+               } else { None };
+
+               let order = RAACommitmentOrder::RevokeAndACKFirst;
+
+               if msg.next_local_commitment_number == our_next_remote_commitment_number {
+                       if required_revoke.is_some() {
+                               log_debug!(self, "Reconnected channel {} with only lost outbound RAA", log_bytes!(self.channel_id()));
+                       } else {
+                               log_debug!(self, "Reconnected channel {} with no loss", log_bytes!(self.channel_id()));
                        }
 
                        if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 {
@@ -2129,22 +2144,71 @@ impl Channel {
                                                        panic!("Got non-channel-failing result from free_holding_cell_htlcs");
                                                }
                                        },
-                                       Ok(Some((commitment_update, channel_monitor))) => return Ok((None, required_revoke, Some(commitment_update), Some(channel_monitor))),
-                                       Ok(None) => return Ok((None, required_revoke, None, None)),
+                                       Ok(Some((commitment_update, channel_monitor))) => return Ok((resend_funding_locked, required_revoke, Some(commitment_update), Some(channel_monitor), order)),
+                                       Ok(None) => return Ok((resend_funding_locked, required_revoke, None, None, order)),
                                }
                        } else {
-                               return Ok((None, required_revoke, None, None));
+                               return Ok((resend_funding_locked, required_revoke, None, None, order));
+                       }
+               } else if msg.next_local_commitment_number == our_next_remote_commitment_number - 1 {
+                       if required_revoke.is_some() {
+                               log_debug!(self, "Reconnected channel {} with lost outbound RAA and lost remote commitment tx", log_bytes!(self.channel_id()));
+                       } else {
+                               log_debug!(self, "Reconnected channel {} with only lost remote commitment tx", log_bytes!(self.channel_id()));
+                       }
+                       let mut update_add_htlcs = Vec::new();
+                       let mut update_fulfill_htlcs = Vec::new();
+                       let mut update_fail_htlcs = Vec::new();
+                       let mut update_fail_malformed_htlcs = Vec::new();
+
+                       for htlc in self.pending_outbound_htlcs.iter() {
+                               if let &OutboundHTLCState::LocalAnnounced(ref onion_packet) = &htlc.state {
+                                       update_add_htlcs.push(msgs::UpdateAddHTLC {
+                                               channel_id: self.channel_id(),
+                                               htlc_id: htlc.htlc_id,
+                                               amount_msat: htlc.amount_msat,
+                                               payment_hash: htlc.payment_hash,
+                                               cltv_expiry: htlc.cltv_expiry,
+                                               onion_routing_packet: (**onion_packet).clone(),
+                                       });
+                               }
                        }
-               } else if msg.next_local_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_remote_commitment_transaction_number {
-                       return Ok((None, required_revoke,
+
+                       for htlc in self.pending_inbound_htlcs.iter() {
+                               if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state {
+                                       match reason {
+                                               &InboundHTLCRemovalReason::FailRelay(ref err_packet) => {
+                                                       update_fail_htlcs.push(msgs::UpdateFailHTLC {
+                                                               channel_id: self.channel_id(),
+                                                               htlc_id: htlc.htlc_id,
+                                                               reason: err_packet.clone()
+                                                       });
+                                               },
+                                               &InboundHTLCRemovalReason::FailMalformed((ref sha256_of_onion, ref failure_code)) => {
+                                                       update_fail_malformed_htlcs.push(msgs::UpdateFailMalformedHTLC {
+                                                               channel_id: self.channel_id(),
+                                                               htlc_id: htlc.htlc_id,
+                                                               sha256_of_onion: sha256_of_onion.clone(),
+                                                               failure_code: failure_code.clone(),
+                                                       });
+                                               },
+                                               &InboundHTLCRemovalReason::Fulfill(ref payment_preimage) => {
+                                                       update_fulfill_htlcs.push(msgs::UpdateFulfillHTLC {
+                                                               channel_id: self.channel_id(),
+                                                               htlc_id: htlc.htlc_id,
+                                                               payment_preimage: payment_preimage.clone(),
+                                                       });
+                                               },
+                                       }
+                               }
+                       }
+
+                       return Ok((resend_funding_locked, required_revoke,
                                        Some(msgs::CommitmentUpdate {
-                                               update_add_htlcs: Vec::new(),
-                                               update_fulfill_htlcs: Vec::new(),
-                                               update_fail_htlcs: Vec::new(),
-                                               update_fail_malformed_htlcs: Vec::new(),
-                                               update_fee: None,
+                                               update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs,
+                                               update_fee: None, //TODO: We need to support re-generating any update_fees in the last commitment_signed!
                                                commitment_signed: self.send_commitment_no_state_update().expect("It looks like we failed to re-generate a commitment_signed we had previously sent?").0,
-                                       }), None));
+                                       }), None, order));
                } else {
                        return Err(ChannelError::Close("Peer attempted to reestablish channel with a very old remote commitment transaction"));
                }
@@ -2225,7 +2289,7 @@ impl Channel {
                        }
                });
                for htlc in self.pending_outbound_htlcs.iter() {
-                       if htlc.state == OutboundHTLCState::LocalAnnounced {
+                       if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
                                return Ok((None, None, dropped_outbound_htlcs));
                        }
                }
@@ -2388,6 +2452,11 @@ impl Channel {
                self.our_htlc_minimum_msat
        }
 
+       /// Allowed in any state (including after shutdown)
+       pub fn get_their_htlc_minimum_msat(&self) -> u64 {
+               self.our_htlc_minimum_msat
+       }
+
        pub fn get_value_satoshis(&self) -> u64 {
                self.channel_value_satoshis
        }
@@ -2501,7 +2570,7 @@ impl Channel {
        /// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
        /// Only returns an ErrorAction of DisconnectPeer, if Err.
        pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, HandleError> {
-               let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
+               let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
                if self.funding_tx_confirmations > 0 {
                        if header.bitcoin_hash() != self.last_block_connected {
                                self.last_block_connected = header.bitcoin_hash();
@@ -2511,10 +2580,10 @@ impl Channel {
                                                self.channel_state |= ChannelState::OurFundingLocked as u32;
                                                true
                                        } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
-                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
+                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
                                                self.channel_update_count += 1;
                                                true
-                                       } else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
                                                // We got a reorg but not enough to trigger a force close, just update
                                                // funding_tx_confirmed_in and return.
                                                false
@@ -2847,7 +2916,7 @@ impl Channel {
                        amount_msat: amount_msat,
                        payment_hash: payment_hash.clone(),
                        cltv_expiry: cltv_expiry,
-                       state: OutboundHTLCState::LocalAnnounced,
+                       state: OutboundHTLCState::LocalAnnounced(Box::new(onion_routing_packet.clone())),
                        source,
                        fail_reason: None,
                });
@@ -2881,7 +2950,7 @@ impl Channel {
                }
                let mut have_updates = self.pending_update_fee.is_some();
                for htlc in self.pending_outbound_htlcs.iter() {
-                       if htlc.state == OutboundHTLCState::LocalAnnounced {
+                       if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
                                have_updates = true;
                        }
                        if have_updates { break; }
@@ -2905,7 +2974,7 @@ impl Channel {
                        }
                }
                for htlc in self.pending_outbound_htlcs.iter_mut() {
-                       if htlc.state == OutboundHTLCState::AwaitingRemoteRevokeToRemove {
+                       if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state {
                                htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke;
                        }
                }
@@ -2974,7 +3043,7 @@ impl Channel {
        /// holding cell HTLCs for payment failure.
        pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, [u8; 32])>), APIError> {
                for htlc in self.pending_outbound_htlcs.iter() {
-                       if htlc.state == OutboundHTLCState::LocalAnnounced {
+                       if let OutboundHTLCState::LocalAnnounced(_) = htlc.state {
                                return Err(APIError::APIMisuseError{err: "Cannot begin shutdown with pending HTLCs. Process pending events first"});
                        }
                }