Merge pull request #890 from TheBlueMatt/2021-04-fix-chan-shutdown-crash
[rust-lightning] / lightning / src / ln / channel.rs
index c13ac9b61ffc94b000f4204ea23baf8a14a0e6aa..8a1489d4ef775c7be7d515bcc3153895437eb726 100644 (file)
@@ -24,7 +24,7 @@ use bitcoin::secp256k1;
 use ln::features::{ChannelFeatures, InitFeatures};
 use ln::msgs;
 use ln::msgs::{DecodeError, OptionalField, DataLossProtect};
-use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+use ln::channelmanager::{BestBlock, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
 use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor};
 use ln::chan_utils;
 use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
@@ -250,7 +250,7 @@ pub const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
 /// Liveness is called to fluctuate given peer disconnecton/monitor failures/closing.
 /// If channel is public, network should have a liveness view announced by us on a
 /// best-effort, which means we may filter out some status transitions to avoid spam.
-/// See further timer_chan_freshness_every_min.
+/// See further timer_tick_occurred.
 #[derive(PartialEq)]
 enum UpdateStatus {
        /// Status has been gossiped.
@@ -377,7 +377,7 @@ pub(super) struct Channel<Signer: Sign> {
 
        /// The hash of the block in which the funding transaction was included.
        funding_tx_confirmed_in: Option<BlockHash>,
-       funding_tx_confirmation_height: u64,
+       funding_tx_confirmation_height: u32,
        short_channel_id: Option<u64>,
 
        counterparty_dust_limit_satoshis: u64,
@@ -1531,7 +1531,7 @@ impl<Signer: Sign> Channel<Signer> {
                &self.get_counterparty_pubkeys().funding_pubkey
        }
 
-       pub fn funding_created<L: Deref>(&mut self, msg: &msgs::FundingCreated, last_block_hash: BlockHash, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor<Signer>), ChannelError> where L::Target: Logger {
+       pub fn funding_created<L: Deref>(&mut self, msg: &msgs::FundingCreated, best_block: BestBlock, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor<Signer>), ChannelError> where L::Target: Logger {
                if self.is_outbound() {
                        return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned()));
                }
@@ -1585,7 +1585,7 @@ impl<Signer: Sign> Channel<Signer> {
                                                          &self.channel_transaction_parameters,
                                                          funding_redeemscript.clone(), self.channel_value_satoshis,
                                                          obscure_factor,
-                                                         holder_commitment_tx, last_block_hash);
+                                                         holder_commitment_tx, best_block);
 
                channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger);
 
@@ -1602,7 +1602,7 @@ impl<Signer: Sign> Channel<Signer> {
 
        /// Handles a funding_signed message from the remote end.
        /// If this call is successful, broadcast the funding transaction (and not before!)
-       pub fn funding_signed<L: Deref>(&mut self, msg: &msgs::FundingSigned, last_block_hash: BlockHash, logger: &L) -> Result<(ChannelMonitor<Signer>, Transaction), ChannelError> where L::Target: Logger {
+       pub fn funding_signed<L: Deref>(&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, logger: &L) -> Result<(ChannelMonitor<Signer>, Transaction), ChannelError> where L::Target: Logger {
                if !self.is_outbound() {
                        return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned()));
                }
@@ -1655,7 +1655,7 @@ impl<Signer: Sign> Channel<Signer> {
                                                          &self.channel_transaction_parameters,
                                                          funding_redeemscript.clone(), self.channel_value_satoshis,
                                                          obscure_factor,
-                                                         holder_commitment_tx, last_block_hash);
+                                                         holder_commitment_tx, best_block);
 
                channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger);
 
@@ -3574,7 +3574,6 @@ impl<Signer: Sign> Channel<Signer> {
                                                                #[cfg(not(feature = "fuzztarget"))]
                                                                panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
                                                        }
-                                                       self.channel_state = ChannelState::ShutdownComplete as u32;
                                                        self.update_time_counter += 1;
                                                        return Err(msgs::ErrorMessage {
                                                                channel_id: self.channel_id(),
@@ -3591,7 +3590,7 @@ impl<Signer: Sign> Channel<Signer> {
                                                                        }
                                                                }
                                                        }
-                                                       self.funding_tx_confirmation_height = height as u64;
+                                                       self.funding_tx_confirmation_height = height;
                                                        self.funding_tx_confirmed_in = Some(*block_hash);
                                                        self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
                                                                Ok(scid) => Some(scid),
@@ -3600,7 +3599,7 @@ impl<Signer: Sign> Channel<Signer> {
                                                }
                                        }
                                        // If we allow 1-conf funding, we may need to check for funding_locked here and
-                                       // send it immediately instead of waiting for an update_best_block call (which
+                                       // send it immediately instead of waiting for a best_block_updated call (which
                                        // may have already happened for this block).
                                        if let Some(funding_locked) = self.check_get_funding_locked(height) {
                                                return Ok(Some(funding_locked));
@@ -3631,7 +3630,7 @@ impl<Signer: Sign> Channel<Signer> {
        ///
        /// May return some HTLCs (and their payment_hash) which have timed out and should be failed
        /// back.
-       pub fn update_best_block(&mut self, height: u32, highest_header_time: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
+       pub fn best_block_updated(&mut self, height: u32, highest_header_time: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
                let mut timed_out_htlcs = Vec::new();
                let unforwarded_htlc_cltv_limit = height + HTLC_FAIL_BACK_BUFFER;
                self.holding_cell_htlc_updates.retain(|htlc_update| {
@@ -3678,6 +3677,32 @@ impl<Signer: Sign> Channel<Signer> {
                Ok((None, timed_out_htlcs))
        }
 
+       /// Indicates the funding transaction is no longer confirmed in the main chain. This may
+       /// force-close the channel, but may also indicate a harmless reorganization of a block or two
+       /// before the channel has reached funding_locked and we can just wait for more blocks.
+       pub fn funding_transaction_unconfirmed(&mut self) -> Result<(), msgs::ErrorMessage> {
+               if self.funding_tx_confirmation_height != 0 {
+                       // We handle the funding disconnection by calling best_block_updated with a height one
+                       // below where our funding was connected, implying a reorg back to conf_height - 1.
+                       let reorg_height = self.funding_tx_confirmation_height - 1;
+                       // We use the time field to bump the current time we set on channel updates if its
+                       // larger. If we don't know that time has moved forward, we can just set it to the last
+                       // time we saw and it will be ignored.
+                       let best_time = self.update_time_counter;
+                       match self.best_block_updated(reorg_height, best_time) {
+                               Ok((funding_locked, timed_out_htlcs)) => {
+                                       assert!(funding_locked.is_none(), "We can't generate a funding with 0 confirmations?");
+                                       assert!(timed_out_htlcs.is_empty(), "We can't have accepted HTLCs with a timeout before our funding confirmation?");
+                                       Ok(())
+                               },
+                               Err(e) => Err(e)
+                       }
+               } else {
+                       // We never learned about the funding confirmation anyway, just ignore
+                       Ok(())
+               }
+       }
+
        // Methods to get unprompted messages to send to the remote end (or where we already returned
        // something in the handler for the message that prompted this message):
 
@@ -4799,7 +4824,7 @@ mod tests {
        use bitcoin::network::constants::Network;
        use bitcoin::hashes::hex::FromHex;
        use hex;
-       use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
+       use ln::channelmanager::{BestBlock, HTLCSource, PaymentPreimage, PaymentHash};
        use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
        use ln::channel::MAX_FUNDING_SATOSHIS;
        use ln::features::InitFeatures;
@@ -5012,8 +5037,8 @@ mod tests {
                let secp_ctx = Secp256k1::new();
                let seed = [42; 32];
                let network = Network::Testnet;
-               let chain_hash = genesis_block(network).header.block_hash();
-               let last_block_hash = chain_hash;
+               let best_block = BestBlock::from_genesis(network);
+               let chain_hash = best_block.block_hash();
                let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
 
                // Go through the flow of opening a channel between two nodes.
@@ -5039,10 +5064,10 @@ mod tests {
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
                let funding_created_msg = node_a_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).unwrap();
-               let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, last_block_hash, &&logger).unwrap();
+               let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, best_block, &&logger).unwrap();
 
                // Node B --> Node A: funding signed
-               let _ = node_a_chan.funding_signed(&funding_signed_msg, last_block_hash, &&logger);
+               let _ = node_a_chan.funding_signed(&funding_signed_msg, best_block, &&logger);
 
                // Now disconnect the two nodes and check that the commitment point in
                // Node B's channel_reestablish message is sane.