X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=fc59c29d7043e72f169931c46ab02aa0e01db364;hb=feb882f6a45ecf78b176a09ed61efc1cdfb43b7f;hp=1279f310d4bfdbcfd134a9b53c95674fa0dd21bf;hpb=2a432c6fa531c707a8fd69d949834f979ef5d81c;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 1279f310..fc59c29d 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -7,7 +7,6 @@ // You may not use this file except in accordance with one or both of these // licenses. -use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType}; use bitcoin::blockdata::opcodes; @@ -22,10 +21,11 @@ use bitcoin::secp256k1::key::{PublicKey,SecretKey}; use bitcoin::secp256k1::{Secp256k1,Signature}; use bitcoin::secp256k1; +use ln::{PaymentPreimage, PaymentHash}; 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, 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}; @@ -251,7 +251,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. @@ -378,7 +378,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, @@ -406,9 +406,9 @@ pub(super) struct Channel { counterparty_forwarding_info: Option, pub(crate) channel_transaction_parameters: ChannelTransactionParameters, + funding_transaction: Option, counterparty_cur_commitment_point: Option, - counterparty_prev_commitment_point: Option, counterparty_node_id: PublicKey, @@ -596,8 +596,9 @@ impl Channel { counterparty_parameters: None, funding_outpoint: None }, - counterparty_cur_commitment_point: None, + funding_transaction: None, + counterparty_cur_commitment_point: None, counterparty_prev_commitment_point: None, counterparty_node_id, @@ -837,8 +838,9 @@ impl Channel { }), funding_outpoint: None }, - counterparty_cur_commitment_point: Some(msg.first_per_commitment_point), + funding_transaction: None, + counterparty_cur_commitment_point: Some(msg.first_per_commitment_point), counterparty_prev_commitment_point: None, counterparty_node_id, @@ -1530,7 +1532,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())); } @@ -1584,7 +1586,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); @@ -1601,7 +1603,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, 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())); } @@ -1654,7 +1656,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); @@ -1663,7 +1665,7 @@ impl Channel { self.cur_holder_commitment_transaction_number -= 1; self.cur_counterparty_commitment_transaction_number -= 1; - Ok(channel_monitor) + Ok((channel_monitor, self.funding_transaction.as_ref().cloned().unwrap())) } pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), ChannelError> { @@ -2764,20 +2766,21 @@ impl Channel { /// Indicates that the latest ChannelMonitor update has been committed by the client /// successfully and we should restore normal operation. Returns messages which should be sent /// to the remote side. - pub fn monitor_updating_restored(&mut self, logger: &L) -> (Option, Option, RAACommitmentOrder, Vec<(PendingHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, bool, Option) where L::Target: Logger { + pub fn monitor_updating_restored(&mut self, logger: &L) -> (Option, Option, RAACommitmentOrder, Vec<(PendingHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, Option, Option) where L::Target: Logger { assert_eq!(self.channel_state & ChannelState::MonitorUpdateFailed as u32, ChannelState::MonitorUpdateFailed as u32); self.channel_state &= !(ChannelState::MonitorUpdateFailed as u32); - let needs_broadcast_safe = self.channel_state & (ChannelState::FundingSent as u32) != 0 && self.is_outbound(); + let funding_broadcastable = if self.channel_state & (ChannelState::FundingSent as u32) != 0 && self.is_outbound() { + self.funding_transaction.take() + } else { None }; - // Because we will never generate a FundingBroadcastSafe event when we're in - // MonitorUpdateFailed, if we assume the user only broadcast the funding transaction when - // they received the FundingBroadcastSafe event, we can only ever hit - // monitor_pending_funding_locked when we're an inbound channel which failed to persist the - // monitor on funding_created, and we even got the funding transaction confirmed before the - // monitor was persisted. + // We will never broadcast the funding transaction when we're in MonitorUpdateFailed (and + // we assume the user never directly broadcasts the funding transaction and waits for us to + // do it). Thus, we can only ever hit monitor_pending_funding_locked when we're an inbound + // channel which failed to persist the monitor on funding_created, and we got the funding + // transaction confirmed before the monitor was persisted. let funding_locked = if self.monitor_pending_funding_locked { - assert!(!self.is_outbound(), "Funding transaction broadcast without FundingBroadcastSafe!"); + assert!(!self.is_outbound(), "Funding transaction broadcast by the local client before it should have - LDK didn't do it!"); self.monitor_pending_funding_locked = false; let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx); Some(msgs::FundingLocked { @@ -2794,7 +2797,7 @@ impl Channel { if self.channel_state & (ChannelState::PeerDisconnected as u32) != 0 { self.monitor_pending_revoke_and_ack = false; self.monitor_pending_commitment_signed = false; - return (None, None, RAACommitmentOrder::RevokeAndACKFirst, forwards, failures, needs_broadcast_safe, funding_locked); + return (None, None, RAACommitmentOrder::RevokeAndACKFirst, forwards, failures, funding_broadcastable, funding_locked); } let raa = if self.monitor_pending_revoke_and_ack { @@ -2808,11 +2811,11 @@ impl Channel { self.monitor_pending_commitment_signed = false; let order = self.resend_order.clone(); log_trace!(logger, "Restored monitor updating resulting in {}{} commitment update and {} RAA, with {} first", - if needs_broadcast_safe { "a funding broadcast safe, " } else { "" }, + if funding_broadcastable.is_some() { "a funding broadcastable, " } else { "" }, if commitment_update.is_some() { "a" } else { "no" }, if raa.is_some() { "an" } else { "no" }, match order { RAACommitmentOrder::CommitmentFirst => "commitment", RAACommitmentOrder::RevokeAndACKFirst => "RAA"}); - (raa, commitment_update, order, forwards, failures, needs_broadcast_safe, funding_locked) + (raa, commitment_update, order, forwards, failures, funding_broadcastable, funding_locked) } pub fn update_fee(&mut self, fee_estimator: &F, msg: &msgs::UpdateFee) -> Result<(), ChannelError> @@ -3502,52 +3505,119 @@ impl Channel { self.network_sync == UpdateStatus::DisabledMarked } - pub fn transactions_confirmed(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData) -> Result<(), msgs::ErrorMessage> { + fn check_get_funding_locked(&mut self, height: u32) -> Option { + if self.funding_tx_confirmation_height == 0 { + return None; + } + + let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; + if funding_tx_confirmations <= 0 { + self.funding_tx_confirmation_height = 0; + } + + if funding_tx_confirmations < self.minimum_depth as i64 { + return None; + } + + let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); + 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 & MULTI_STATE_FLAGS); + self.update_time_counter += 1; + true + } 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 ignore. + false + } else if self.channel_state < ChannelState::ChannelFunded as u32 { + 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 ignore. + false + }; + + if need_commitment_update { + if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { + let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx); + return Some(msgs::FundingLocked { + channel_id: self.channel_id, + next_per_commitment_point, + }); + } else { + self.monitor_pending_funding_locked = true; + } + } + None + } + + /// When a transaction is confirmed, we check whether it is or spends the funding transaction + /// In the first case, we store the confirmation height and calculating the short channel id. + /// In the second, we simply return an Err indicating we need to be force-closed now. + pub fn transactions_confirmed(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData, logger: &L) + -> Result, msgs::ErrorMessage> where L::Target: Logger { let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); - if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 { - for &(index_in_block, tx) in txdata.iter() { - let funding_txo = self.get_funding_txo().unwrap(); - if tx.txid() == funding_txo.txid { - let txo_idx = funding_txo.index as usize; - if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() || - tx.output[txo_idx].value != self.channel_value_satoshis { - if self.is_outbound() { - // If we generated the funding transaction and it doesn't match what it - // should, the client is really broken and we should just panic and - // tell them off. That said, because hash collisions happen with high - // probability in fuzztarget mode, if we're fuzzing we just close the - // channel and move on. - #[cfg(not(feature = "fuzztarget"))] - panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); + for &(index_in_block, tx) in txdata.iter() { + if let Some(funding_txo) = self.get_funding_txo() { + // If we haven't yet sent a funding_locked, but are in FundingSent (ignoring + // whether they've sent a funding_locked or not), check if we should send one. + if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 { + if tx.txid() == funding_txo.txid { + let txo_idx = funding_txo.index as usize; + if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() || + tx.output[txo_idx].value != self.channel_value_satoshis { + if self.is_outbound() { + // If we generated the funding transaction and it doesn't match what it + // should, the client is really broken and we should just panic and + // tell them off. That said, because hash collisions happen with high + // probability in fuzztarget mode, if we're fuzzing we just close the + // channel and move on. + #[cfg(not(feature = "fuzztarget"))] + panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); + } + self.update_time_counter += 1; + return Err(msgs::ErrorMessage { + channel_id: self.channel_id(), + data: "funding tx had wrong script/value or output index".to_owned() + }); + } else { + if self.is_outbound() { + for input in tx.input.iter() { + if input.witness.is_empty() { + // We generated a malleable funding transaction, implying we've + // just exposed ourselves to funds loss to our counterparty. + #[cfg(not(feature = "fuzztarget"))] + panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); + } + } + } + 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), + Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"), + } } - self.channel_state = ChannelState::ShutdownComplete as u32; - self.update_time_counter += 1; + } + // If we allow 1-conf funding, we may need to check for funding_locked here and + // 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)); + } + } + for inp in tx.input.iter() { + if inp.previous_output == funding_txo.into_bitcoin_outpoint() { + log_trace!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.channel_id())); return Err(msgs::ErrorMessage { channel_id: self.channel_id(), - data: "funding tx had wrong script/value".to_owned() + data: "Commitment or closing transaction was confirmed on chain.".to_owned() }); - } else { - if self.is_outbound() { - for input in tx.input.iter() { - if input.witness.is_empty() { - // We generated a malleable funding transaction, implying we've - // just exposed ourselves to funds loss to our counterparty. - #[cfg(not(feature = "fuzztarget"))] - panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); - } - } - } - self.funding_tx_confirmation_height = height as u64; - 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), - Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"), - } } } } } - Ok(()) + Ok(None) } /// When a new block is connected, we check the height of the block against outbound holding @@ -3561,7 +3631,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| { @@ -3577,91 +3647,61 @@ impl Channel { }); self.update_time_counter = cmp::max(self.update_time_counter, highest_header_time); - if self.funding_tx_confirmation_height > 0 { - let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; - if funding_tx_confirmations <= 0 { - self.funding_tx_confirmation_height = 0; + + if let Some(funding_locked) = self.check_get_funding_locked(height) { + return Ok((Some(funding_locked), timed_out_htlcs)); + } + + let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); + if non_shutdown_state >= ChannelState::ChannelFunded as u32 || + (non_shutdown_state & ChannelState::OurFundingLocked as u32) == ChannelState::OurFundingLocked as u32 { + let mut funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; + if self.funding_tx_confirmation_height == 0 { + // Note that check_get_funding_locked may reset funding_tx_confirmation_height to + // zero if it has been reorged out, however in either case, our state flags + // indicate we've already sent a funding_locked + funding_tx_confirmations = 0; } - let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); - if (non_shutdown_state >= ChannelState::ChannelFunded as u32 || - (non_shutdown_state & ChannelState::OurFundingLocked as u32) == ChannelState::OurFundingLocked as u32) && - funding_tx_confirmations < self.minimum_depth as i64 / 2 { + // If we've sent funding_locked (or have both sent and received funding_locked), and + // the funding transaction's confirmation count has dipped below minimum_depth / 2, + // close the channel and hope we can get the latest state on chain (because presumably + // the funding transaction is at least still in the mempool of most nodes). + if funding_tx_confirmations < self.minimum_depth as i64 / 2 { return Err(msgs::ErrorMessage { channel_id: self.channel_id(), data: format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth, funding_tx_confirmations), }); } - - if funding_tx_confirmations == self.minimum_depth as i64 { - 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 & MULTI_STATE_FLAGS); - self.update_time_counter += 1; - true - } 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 - } else if self.channel_state < ChannelState::ChannelFunded as u32 { - 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 - }; - - //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. - if need_commitment_update { - if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { - let next_per_commitment_point = self.holder_signer.get_per_commitment_point(self.cur_holder_commitment_transaction_number, &self.secp_ctx); - return Ok((Some(msgs::FundingLocked { - channel_id: self.channel_id, - next_per_commitment_point, - }), timed_out_htlcs)); - } else { - self.monitor_pending_funding_locked = true; - return Ok((None, timed_out_htlcs)); - } - } - } } Ok((None, timed_out_htlcs)) } - /// When we receive a new block, we (a) check whether the block contains the funding - /// transaction (which would start us counting blocks until we send the funding_signed), and - /// (b) check the height of the block against outbound holding cell HTLCs in case we need to - /// give up on them prematurely and time them out. Everything else (e.g. commitment - /// transaction broadcasts, channel closure detection, HTLC transaction broadcasting, etc) is - /// handled by the ChannelMonitor. - /// - /// If we return 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. - /// - /// May return some HTLCs (and their payment_hash) which have timed out and should be failed - /// back. - pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { - self.transactions_confirmed(&header.block_hash(), height, txdata)?; - self.update_best_block(height, header.time) - } - - /// Called by channelmanager based on chain blocks being disconnected. - /// Returns true if we need to close the channel now due to funding transaction - /// unconfirmation/reorg. - pub fn block_disconnected(&mut self, header: &BlockHeader, new_height: u32) -> bool { - if self.update_best_block(new_height, header.time).is_err() { - return true; + /// 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(()) } - false } // Methods to get unprompted messages to send to the remote end (or where we already returned @@ -3753,7 +3793,7 @@ impl Channel { /// Note that channel_id changes during this call! /// Do NOT broadcast the funding transaction until after a successful funding_signed call! /// If an Err is returned, it is a ChannelError::Close. - pub fn get_outbound_funding_created(&mut self, funding_txo: OutPoint, logger: &L) -> Result where L::Target: Logger { + pub fn get_outbound_funding_created(&mut self, funding_transaction: Transaction, funding_txo: OutPoint, logger: &L) -> Result where L::Target: Logger { if !self.is_outbound() { panic!("Tried to create outbound funding_created message on an inbound channel!"); } @@ -3784,6 +3824,7 @@ impl Channel { self.channel_state = ChannelState::FundingCreated as u32; self.channel_id = funding_txo.to_channel_id(); + self.funding_transaction = Some(funding_transaction); Ok(msgs::FundingCreated { temporary_channel_id, @@ -4508,8 +4549,9 @@ impl Writeable for Channel { } self.channel_transaction_parameters.write(writer)?; - self.counterparty_cur_commitment_point.write(writer)?; + self.funding_transaction.write(writer)?; + self.counterparty_cur_commitment_point.write(writer)?; self.counterparty_prev_commitment_point.write(writer)?; self.counterparty_node_id.write(writer)?; @@ -4678,6 +4720,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel }; let channel_parameters = Readable::read(reader)?; + let funding_transaction = Readable::read(reader)?; + let counterparty_cur_commitment_point = Readable::read(reader)?; let counterparty_prev_commitment_point = Readable::read(reader)?; @@ -4750,8 +4794,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel counterparty_forwarding_info, channel_transaction_parameters: channel_parameters, - counterparty_cur_commitment_point, + funding_transaction, + counterparty_cur_commitment_point, counterparty_prev_commitment_point, counterparty_node_id, @@ -4780,15 +4825,16 @@ mod tests { use bitcoin::network::constants::Network; use bitcoin::hashes::hex::FromHex; use hex; - use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; - use ln::channel::{Channel,Sign,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys}; + use ln::{PaymentPreimage, PaymentHash}; + use ln::channelmanager::{BestBlock, HTLCSource}; + use ln::channel::{Channel,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys}; use ln::channel::MAX_FUNDING_SATOSHIS; use ln::features::InitFeatures; use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate}; use ln::chan_utils; use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT}; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; - use chain::keysinterface::{InMemorySigner, KeysInterface}; + use chain::keysinterface::{InMemorySigner, KeysInterface, BaseSign}; use chain::transaction::OutPoint; use util::config::UserConfig; use util::enforcing_trait_impls::EnforcingSigner; @@ -4797,6 +4843,7 @@ mod tests { use bitcoin::secp256k1::{Secp256k1, Message, Signature, All}; use bitcoin::secp256k1::ffi::Signature as FFISignature; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; + use bitcoin::secp256k1::recovery::RecoverableSignature; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::hash_types::{Txid, WPubkeyHash}; @@ -4842,6 +4889,7 @@ mod tests { } fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] } fn read_chan_signer(&self, _data: &[u8]) -> Result { panic!(); } + fn sign_invoice(&self, _invoice_preimage: Vec) -> Result { panic!(); } } fn public_from_secret_hex(secp_ctx: &Secp256k1, hex: &str) -> PublicKey { @@ -4993,8 +5041,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. @@ -5019,11 +5067,11 @@ mod tests { value: 10000000, script_pubkey: output_script.clone(), }]}; let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 }; - let funding_created_msg = node_a_chan.get_outbound_funding_created(funding_outpoint, &&logger).unwrap(); - let (funding_signed_msg, _) = node_b_chan.funding_created(&funding_created_msg, last_block_hash, &&logger).unwrap(); + 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, 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.