Implement HandleError event with ErrorAction field
[rust-lightning] / src / ln / channel.rs
index 978be08dc217e4284ef576473a7538fd677ce549..68a23dc67b9348dac07e795e5b8c9d50555470ed 100644 (file)
@@ -14,7 +14,7 @@ use crypto::digest::Digest;
 use crypto::hkdf::{hkdf_extract,hkdf_expand};
 
 use ln::msgs;
-use ln::msgs::{HandleError, MsgEncodable};
+use ln::msgs::{ErrorAction, HandleError, MsgEncodable};
 use ln::channelmonitor::ChannelMonitor;
 use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason};
 use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT};
@@ -24,6 +24,7 @@ use chain::transaction::OutPoint;
 use util::{transaction_utils,rng};
 use util::sha2::Sha256;
 
+use std;
 use std::default::Default;
 use std::{cmp,mem};
 use std::time::Instant;
@@ -135,7 +136,7 @@ enum HTLCState {
        /// anyway).
        LocalRemoved,
        /// Removed by us, sent a new commitment_signed and got a revoke_and_ack. Just waiting on an
-       /// updated local commitment transaction.
+       /// updated local commitment transaction. Implies local_removed_fulfilled.
        LocalRemovedAwaitingCommitment,
 }
 
@@ -270,7 +271,7 @@ pub struct Channel {
        /// to detect unconfirmation after a serialize-unserialize roudtrip where we may not see a full
        /// series of block_connected/block_disconnected calls. Obviously this is not a guarantee as we
        /// could miss the funding_tx_confirmed_in block as well, but it serves as a useful fallback.
-       funding_tx_confirmed_in: Sha256dHash,
+       funding_tx_confirmed_in: Option<Sha256dHash>,
        short_channel_id: Option<u64>,
        /// Used to deduplicate block_connected callbacks
        last_block_connected: Sha256dHash,
@@ -400,7 +401,7 @@ impl Channel {
 
                        last_sent_closing_fee: None,
 
-                       funding_tx_confirmed_in: Default::default(),
+                       funding_tx_confirmed_in: None,
                        short_channel_id: None,
                        last_block_connected: Default::default(),
                        funding_tx_confirmations: 0,
@@ -518,7 +519,7 @@ impl Channel {
 
                        last_sent_closing_fee: None,
 
-                       funding_tx_confirmed_in: Default::default(),
+                       funding_tx_confirmed_in: None,
                        short_channel_id: None,
                        last_block_connected: Default::default(),
                        funding_tx_confirmations: 0,
@@ -662,7 +663,7 @@ impl Channel {
                        } else {
                                match htlc.state {
                                        HTLCState::AwaitingRemoteRevokeToRemove|HTLCState::AwaitingRemovedRemoteRevoke => {
-                                               if generated_by_local && htlc.fail_reason.is_none() {
+                                               if htlc.fail_reason.is_none() {
                                                        value_to_self_msat_offset -= htlc.amount_msat as i64;
                                                }
                                        },
@@ -677,6 +678,7 @@ impl Channel {
                                                }
                                        },
                                        HTLCState::LocalRemovedAwaitingCommitment => {
+                                               assert!(htlc.local_removed_fulfilled);
                                                value_to_self_msat_offset += htlc.amount_msat as i64;
                                        },
                                        _ => {},
@@ -927,7 +929,7 @@ impl Channel {
                Ok(our_sig)
        }
 
-       pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, ChannelMonitor)>, HandleError> {
+       fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result<(Option<msgs::UpdateFulfillHTLC>, Option<ChannelMonitor>), HandleError> {
                // Either ChannelFunded got set (which means it wont bet unset) or there is no way any
                // caller thought we could have something claimed (cause we wouldn't have accepted in an
                // incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us,
@@ -942,13 +944,31 @@ impl Channel {
                let mut payment_hash_calc = [0; 32];
                sha.result(&mut payment_hash_calc);
 
+               let mut pending_idx = std::usize::MAX;
+               for (idx, htlc) in self.pending_htlcs.iter().enumerate() {
+                       if !htlc.outbound && htlc.payment_hash == payment_hash_calc {
+                               if pending_idx != std::usize::MAX {
+                                       panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!");
+                               }
+                               pending_idx = idx;
+                       }
+               }
+               if pending_idx == std::usize::MAX {
+                       return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+               }
+
                // Now update local state:
+               //
+               // We have to put the payment_preimage in the channel_monitor right away here to ensure we
+               // can claim it even if the channel hits the chain before we see their next commitment.
+               self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
+
                if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) {
                        for pending_update in self.holding_cell_htlc_updates.iter() {
                                match pending_update {
                                        &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, .. } => {
                                                if payment_preimage_arg == *payment_preimage {
-                                                       return Ok(None);
+                                                       return Ok((None, None));
                                                }
                                        },
                                        &HTLCUpdateAwaitingACK::FailHTLC { ref payment_hash, .. } => {
@@ -962,49 +982,39 @@ impl Channel {
                        self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC {
                                payment_preimage: payment_preimage_arg, payment_hash: payment_hash_calc,
                        });
-                       return Ok(None);
-               }
-
-               let mut htlc_id = 0;
-               let mut htlc_amount_msat = 0;
-               for htlc in self.pending_htlcs.iter_mut() {
-                       if !htlc.outbound && htlc.payment_hash == payment_hash_calc {
-                               if htlc_id != 0 {
-                                       panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!");
-                               }
-                               htlc_id = htlc.htlc_id;
-                               htlc_amount_msat += htlc.amount_msat;
-                               if htlc.state == HTLCState::Committed {
-                                       htlc.state = HTLCState::LocalRemoved;
-                                       htlc.local_removed_fulfilled = true;
-                               } else if htlc.state == HTLCState::RemoteAnnounced {
-                                       panic!("Somehow forwarded HTLC prior to remote revocation!");
-                               } else if htlc.state == HTLCState::LocalRemoved || htlc.state == HTLCState::LocalRemovedAwaitingCommitment {
-                                       return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
-                               } else {
-                                       panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
-                               }
+                       return Ok((None, Some(self.channel_monitor.clone())));
+               }
+
+               let htlc_id = {
+                       let htlc = &mut self.pending_htlcs[pending_idx];
+                       if htlc.state == HTLCState::Committed {
+                               htlc.state = HTLCState::LocalRemoved;
+                               htlc.local_removed_fulfilled = true;
+                       } else if htlc.state == HTLCState::RemoteAnnounced {
+                               panic!("Somehow forwarded HTLC prior to remote revocation!");
+                       } else if htlc.state == HTLCState::LocalRemoved || htlc.state == HTLCState::LocalRemovedAwaitingCommitment {
+                               return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
+                       } else {
+                               panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state");
                        }
-               }
-               if htlc_amount_msat == 0 {
-                       return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None});
-               }
-               self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg);
+                       htlc.htlc_id
+               };
 
-               Ok(Some((msgs::UpdateFulfillHTLC {
+               Ok((Some(msgs::UpdateFulfillHTLC {
                        channel_id: self.channel_id(),
                        htlc_id: htlc_id,
                        payment_preimage: payment_preimage_arg,
-               }self.channel_monitor.clone())))
+               }), Some(self.channel_monitor.clone())))
        }
 
-       pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned, ChannelMonitor)>, HandleError> {
+       pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option<ChannelMonitor>), HandleError> {
                match self.get_update_fulfill_htlc(payment_preimage)? {
-                       Some(update_fulfill_htlc) => {
+                       (Some(update_fulfill_htlc), _) => {
                                let (commitment, monitor_update) = self.send_commitment_no_status_check()?;
-                               Ok(Some((update_fulfill_htlc.0, commitment, monitor_update)))
+                               Ok((Some((update_fulfill_htlc, commitment)), Some(monitor_update)))
                        },
-                       None => Ok(None)
+                       (None, Some(channel_monitor)) => Ok((None, Some(channel_monitor))),
+                       (None, None) => Ok((None, None))
                }
        }
 
@@ -1347,7 +1357,7 @@ impl Channel {
                Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", action: None})
        }
 
-       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<ChannelMonitor, HandleError> {
+       pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(), HandleError> {
                if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
                        return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None});
                }
@@ -1357,9 +1367,8 @@ impl Channel {
                let mut payment_hash = [0; 32];
                sha.result(&mut payment_hash);
 
-               self.channel_monitor.provide_payment_preimage(&payment_hash, &msg.payment_preimage);
                self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?;
-               Ok(self.channel_monitor.clone())
+               Ok(())
        }
 
        pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> {
@@ -1491,7 +1500,7 @@ impl Channel {
                                                },
                                                &HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, .. } => {
                                                        match self.get_update_fulfill_htlc(payment_preimage) {
-                                                               Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap().0),
+                                                               Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.0.unwrap()),
                                                                Err(e) => {
                                                                        err = Some(e);
                                                                }
@@ -1818,6 +1827,7 @@ impl Channel {
                self.user_id
        }
 
+       /// May only be called after funding has been initiated (ie is_funding_initiated() is true)
        pub fn channel_monitor(&self) -> ChannelMonitor {
                if self.channel_state < ChannelState::FundingCreated as u32 {
                        panic!("Can't get a channel monitor until funding has been created");
@@ -1827,6 +1837,7 @@ impl Channel {
 
        /// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus,
        /// is_usable() returns true).
+       /// Allowed in any state (including after shutdown)
        pub fn get_short_channel_id(&self) -> Option<u64> {
                self.short_channel_id
        }
@@ -1837,10 +1848,12 @@ impl Channel {
                self.channel_monitor.get_funding_txo()
        }
 
+       /// Allowed in any state (including after shutdown)
        pub fn get_their_node_id(&self) -> PublicKey {
                self.their_node_id
        }
 
+       /// Allowed in any state (including after shutdown)
        pub fn get_our_htlc_minimum_msat(&self) -> u64 {
                self.our_htlc_minimum_msat
        }
@@ -1849,6 +1862,7 @@ impl Channel {
                self.channel_value_satoshis
        }
 
+       /// Allowed in any state (including after shutdown)
        pub fn get_channel_update_count(&self) -> u32 {
                self.channel_update_count
        }
@@ -1858,6 +1872,7 @@ impl Channel {
        }
 
        /// Gets the fee we'd want to charge for adding an HTLC output to this Channel
+       /// Allowed in any state (including after shutdown)
        pub fn get_our_fee_base_msat(&self, fee_estimator: &FeeEstimator) -> u32 {
                // For lack of a better metric, we calculate what it would cost to consolidate the new HTLC
                // output value back into a transaction with the regular channel output:
@@ -1877,6 +1892,7 @@ impl Channel {
        }
 
        /// Returns true if this channel is fully established and not known to be closing.
+       /// Allowed in any state (including after shutdown)
        pub fn is_usable(&self) -> bool {
                let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK;
                (self.channel_state & mask) == (ChannelState::ChannelFunded as u32)
@@ -1884,10 +1900,16 @@ impl Channel {
 
        /// Returns true if this channel is currently available for use. This is a superset of
        /// is_usable() and considers things like the channel being temporarily disabled.
+       /// Allowed in any state (including after shutdown)
        pub fn is_live(&self) -> bool {
                self.is_usable()
        }
 
+       /// Returns true if funding_created was sent/received.
+       pub fn is_funding_initiated(&self) -> bool {
+               self.channel_state >= ChannelState::FundingCreated as u32
+       }
+
        /// Returns true if this channel is fully shut down. True here implies that no further actions
        /// may/will be taken on this channel, and thus this object should be freed. Any future changes
        /// will be handled appropriately by the chain monitor.
@@ -1901,34 +1923,48 @@ impl Channel {
        /// Called by channelmanager based on chain blocks being connected.
        /// Note that we only need to use this to detect funding_signed, anything else is handled by
        /// the channel_monitor.
-       pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Option<msgs::FundingLocked> {
+       /// In case of Err, the channel may have been closed, at which point the standard requirements
+       /// 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);
                if self.funding_tx_confirmations > 0 {
                        if header.bitcoin_hash() != self.last_block_connected {
                                self.last_block_connected = header.bitcoin_hash();
                                self.funding_tx_confirmations += 1;
                                if self.funding_tx_confirmations == CONF_TARGET as u64 {
-                                       if non_shutdown_state == ChannelState::FundingSent as u32 {
+                                       let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
                                                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_update_count += 1;
-                                               //TODO: Something about a state where we "lost confirmation"
+                                               true
+                                       } else if self.channel_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
                                        } else if self.channel_state < ChannelState::ChannelFunded as u32 {
-                                               panic!("Started confirming a channel in a state pre-FundingSent?");
-                                       }
-                                       self.funding_tx_confirmed_in = header.bitcoin_hash();
+                                               panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
+                                       } else {
+                                               // We got a reorg but not enough to trigger a force close, just update
+                                               // funding_tx_confirmed_in and return.
+                                               false
+                                       };
+                                       self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
 
                                        //TODO: Note that this must be a duplicate of the previous commitment point they sent us,
                                        //as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
                                        //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be
                                        //a protocol oversight, but I assume I'm just missing something.
-                                       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).unwrap();
-                                       return Some(msgs::FundingLocked {
-                                               channel_id: self.channel_id,
-                                               next_per_commitment_point: next_per_commitment_point,
-                                       });
+                                       if need_commitment_update {
+                                               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).unwrap();
+                                               return Ok(Some(msgs::FundingLocked {
+                                                       channel_id: self.channel_id,
+                                                       next_per_commitment_point: next_per_commitment_point,
+                                               }));
+                                       }
                                }
                        }
                }
@@ -1940,6 +1976,7 @@ impl Channel {
                                                tx.output[txo_idx].value != self.channel_value_satoshis {
                                                self.channel_state = ChannelState::ShutdownComplete as u32;
                                                self.channel_update_count += 1;
+                                               return Err(HandleError{err: "funding tx had wrong script/value", action: Some(ErrorAction::DisconnectPeer{msg: None})});
                                        } else {
                                                self.funding_tx_confirmations = 1;
                                                self.short_channel_id = Some(((height as u64)          << (5*8)) |
@@ -1949,7 +1986,7 @@ impl Channel {
                                }
                        }
                }
-               None
+               Ok(None)
        }
 
        /// Called by channelmanager based on chain blocks being disconnected.
@@ -1962,7 +1999,7 @@ impl Channel {
                                return true;
                        }
                }
-               if header.bitcoin_hash() == self.funding_tx_confirmed_in {
+               if Some(header.bitcoin_hash()) == self.funding_tx_confirmed_in {
                        self.funding_tx_confirmations = CONF_TARGET as u64 - 1;
                }
                false
@@ -2323,14 +2360,39 @@ impl Channel {
        }
 
        /// Gets the latest commitment transaction and any dependant transactions for relay (forcing
-       /// shutdown of this channel - no more calls into this Channel may be made afterwards.
-       pub fn force_shutdown(&mut self) -> Vec<Transaction> {
+       /// shutdown of this channel - no more calls into this Channel may be made afterwards except
+       /// those explicitly stated to be allowed after shutdown completes, eg some simple getters).
+       /// Also returns the list of payment_hashes for channels which we can safely fail backwards
+       /// immediately (others we will have to allow to time out).
+       pub fn force_shutdown(&mut self) -> (Vec<Transaction>, Vec<[u8; 32]>) {
                assert!(self.channel_state != ChannelState::ShutdownComplete as u32);
+
+               // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and
+               // return them to fail the payment.
+               let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len());
+               for htlc_update in self.holding_cell_htlc_updates.drain(..) {
+                       match htlc_update {
+                               HTLCUpdateAwaitingACK::AddHTLC { payment_hash, .. } => {
+                                       dropped_outbound_htlcs.push(payment_hash);
+                               },
+                               _ => {}
+                       }
+               }
+
+               for htlc in self.pending_htlcs.drain(..) {
+                       if htlc.state == HTLCState::LocalAnnounced {
+                               dropped_outbound_htlcs.push(htlc.payment_hash);
+                       }
+                       //TODO: Do something with the remaining HTLCs
+                       //(we need to have the ChannelManager monitor them so we can claim the inbound HTLCs
+                       //which correspond)
+               }
+
                self.channel_state = ChannelState::ShutdownComplete as u32;
                self.channel_update_count += 1;
                let mut res = Vec::new();
                mem::swap(&mut res, &mut self.last_local_commitment_txn);
-               res
+               (res, dropped_outbound_htlcs)
        }
 }