X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=8a1489d4ef775c7be7d515bcc3153895437eb726;hb=6b9ec8b6e6c6ecb8a405611bf52b960d66d657a8;hp=63f730781a6b6a56e71f10586d6286f193b3a38c;hpb=eee1c30ea6592463d41eefad8306223ec5548014;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 63f73078..8a1489d4 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -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}; @@ -377,7 +377,7 @@ pub(super) struct Channel { /// The hash of the block in which the funding transaction was included. funding_tx_confirmed_in: Option, - funding_tx_confirmation_height: u64, + funding_tx_confirmation_height: u32, short_channel_id: Option, counterparty_dust_limit_satoshis: u64, @@ -1531,7 +1531,7 @@ impl Channel { &self.get_counterparty_pubkeys().funding_pubkey } - pub fn funding_created(&mut self, msg: &msgs::FundingCreated, last_block_hash: BlockHash, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> where L::Target: Logger { + pub fn funding_created(&mut self, msg: &msgs::FundingCreated, best_block: BestBlock, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor), 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 Channel { &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 Channel { /// 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(&mut self, msg: &msgs::FundingSigned, last_block_hash: BlockHash, logger: &L) -> Result<(ChannelMonitor, Transaction), ChannelError> where L::Target: Logger { + pub fn funding_signed(&mut self, msg: &msgs::FundingSigned, best_block: BestBlock, logger: &L) -> Result<(ChannelMonitor, 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 Channel { &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 Channel { #[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 Channel { } } } - 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 Channel { } } // 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 Channel { /// /// 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, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { + pub fn best_block_updated(&mut self, height: u32, highest_header_time: u32) -> Result<(Option, 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 Channel { 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.