X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=c5908906a076b7251f7f918d815626a5f5b32fb4;hb=7159d1546ae92281a7e0533813a6e7558f16354a;hp=ac072c0ea4f4f3de84fa6ca2fcfcfeda16085930;hpb=80055d4bb41b83428f74141c0140165add2609a7;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index ac072c0e..c5908906 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -18,7 +18,7 @@ use secp256k1; use ln::features::{ChannelFeatures, InitFeatures}; use ln::msgs; use ln::msgs::{DecodeError, OptionalField, DataLossProtect}; -use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep}; +use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER}; use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT}; use ln::chan_utils::{CounterpartyCommitmentSecrets, LocalCommitmentTransaction, TxCreationKeys, HTLCOutputInCommitment, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT, make_funding_redeemscript, ChannelPublicKeys}; use ln::chan_utils; @@ -207,8 +207,8 @@ enum ChannelState { /// to drop us, but we store this anyway. ShutdownComplete = 4096, } -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 | ChannelState::MonitorUpdateFailed as u32); +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 | ChannelState::MonitorUpdateFailed as u32; const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1; @@ -382,7 +382,7 @@ pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; /// Maximmum `funding_satoshis` value, according to the BOLT #2 specification /// it's 2^24. -pub const MAX_FUNDING_SATOSHIS: u64 = (1 << 24); +pub const MAX_FUNDING_SATOSHIS: u64 = 1 << 24; /// Used to return a simple Error back to ChannelManager. Will get converted to a /// msgs::ErrorAction::SendErrorMessage or msgs::ErrorAction::IgnoreError as appropriate with our @@ -1727,8 +1727,6 @@ impl Channel { return Err(ChannelError::Close("Remote provided CLTV expiry in seconds instead of block height")); } - //TODO: Check msg.cltv_expiry further? Do this in channel manager? - if self.channel_state & ChannelState::LocalShutdownSent as u32 != 0 { if let PendingHTLCStatus::Forward(_) = pending_forward_state { panic!("ChannelManager shouldn't be trying to add a forwardable HTLC after we've started closing"); @@ -3154,13 +3152,33 @@ impl Channel { self.network_sync == UpdateStatus::DisabledMarked } - /// 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. - /// 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. + /// 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. - pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result, msgs::ErrorMessage> { + /// + /// 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, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { + let mut timed_out_htlcs = Vec::new(); + self.holding_cell_htlc_updates.retain(|htlc_update| { + match htlc_update { + &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, .. } => { + if *cltv_expiry <= height + HTLC_FAIL_BACK_BUFFER { + timed_out_htlcs.push((source.clone(), payment_hash.clone())); + false + } else { true } + }, + _ => true + } + }); let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); if header.bitcoin_hash() != self.last_block_connected { if self.funding_tx_confirmations > 0 { @@ -3243,19 +3261,19 @@ impl Channel { if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 { 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 { + return Ok((Some(msgs::FundingLocked { channel_id: self.channel_id, next_per_commitment_point: next_per_commitment_point, - })); + }), timed_out_htlcs)); } else { self.monitor_pending_funding_locked = true; - return Ok(None); + return Ok((None, timed_out_htlcs)); } } } } } - Ok(None) + Ok((None, timed_out_htlcs)) } /// Called by channelmanager based on chain blocks being disconnected. @@ -3539,8 +3557,6 @@ impl Channel { return Err(ChannelError::Ignore("Cannot send value that would put us over their reserve value")); } - //TODO: Check cltv_expiry? Do this in channel manager? - // Now update local state: if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == (ChannelState::AwaitingRemoteRevoke as u32) { self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::AddHTLC { @@ -4479,7 +4495,7 @@ mod tests { macro_rules! test_commitment { ( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr, { $( { $htlc_idx: expr, $their_htlc_sig_hex: expr, $our_htlc_sig_hex: expr, $htlc_tx_hex: expr } ), * - } ) => { + } ) => { { unsigned_tx = { let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw); let htlcs = res.2.drain(..) @@ -4501,11 +4517,15 @@ mod tests { assert_eq!(unsigned_tx.1.len(), per_htlc.len()); localtx = LocalCommitmentTransaction::new_missing_local_sig(unsigned_tx.0.clone(), &their_signature, &PublicKey::from_secret_key(&secp_ctx, chan.local_keys.funding_key()), chan.their_funding_pubkey(), keys.clone(), chan.feerate_per_kw, per_htlc); - chan_keys.sign_local_commitment(&mut localtx, &chan.secp_ctx); + let local_sig = chan_keys.sign_local_commitment(&localtx, &chan.secp_ctx).unwrap(); + localtx.add_local_sig(&redeemscript, local_sig); assert_eq!(serialize(localtx.with_valid_witness())[..], hex::decode($tx_hex).unwrap()[..]); + let htlc_sigs = chan_keys.sign_local_commitment_htlc_transactions(&localtx, chan.their_to_self_delay, &chan.secp_ctx).unwrap(); + let mut htlc_sig_iter = localtx.per_htlc.iter().zip(htlc_sigs.iter().enumerate()); + $({ let remote_signature = Signature::from_der(&hex::decode($their_htlc_sig_hex).unwrap()[..]).unwrap(); @@ -4527,12 +4547,19 @@ mod tests { assert!(preimage.is_some()); } - chan_keys.sign_htlc_transaction(&mut localtx, $htlc_idx, preimage, chan.their_to_self_delay, &chan.secp_ctx); + let mut htlc_sig = htlc_sig_iter.next().unwrap(); + while (htlc_sig.1).1.is_none() { htlc_sig = htlc_sig_iter.next().unwrap(); } + assert_eq!((htlc_sig.0).0.transaction_output_index, Some($htlc_idx)); - assert_eq!(serialize(localtx.htlc_with_valid_witness($htlc_idx).as_ref().unwrap())[..], + assert_eq!(serialize(&localtx.get_signed_htlc_tx((htlc_sig.1).0, &(htlc_sig.1).1.unwrap(), &preimage, chan.their_to_self_delay))[..], hex::decode($htlc_tx_hex).unwrap()[..]); })* - } + loop { + let htlc_sig = htlc_sig_iter.next(); + if htlc_sig.is_none() { break; } + assert!((htlc_sig.unwrap().1).1.is_none()); + } + } } } {