X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=src%2Fln%2Fchannel.rs;h=b207baa9fe9c08162197f1896cff81709fd84b24;hb=fe90e13f841548f2be0594854216c85889e71584;hp=3c605859dff193385c53a50fc137a737ea92f4d8;hpb=ca712dfa36016334f0f91eed6ebc377175e2727b;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 3c605859..b207baa9 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -14,7 +14,7 @@ use crypto::digest::Digest; use crypto::hkdf::{hkdf_extract,hkdf_expand}; use ln::msgs; -use ln::msgs::{ErrorAction, HandleError, MsgEncodable}; +use ln::msgs::{ErrorAction, HandleError}; use ln::channelmonitor::ChannelMonitor; use ln::channelmanager::{PendingHTLCStatus, HTLCSource, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg}; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; @@ -22,6 +22,7 @@ use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; use chain::transaction::OutPoint; use util::{transaction_utils,rng}; +use util::ser::Writeable; use util::sha2::Sha256; use util::logger::Logger; use util::errors::APIError; @@ -256,11 +257,13 @@ enum ChannelState { } const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32); +const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1; + // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking // has been completed, and then turn into a Channel to get compiler-time enforcement of things like // calling channel_id() before we're set up or things like get_outbound_funding_signed on an // inbound channel. -pub struct Channel { +pub(super) struct Channel { user_id: u64, channel_id: [u8; 32], @@ -436,8 +439,8 @@ impl Channel { channel_value_satoshis: channel_value_satoshis, local_keys: chan_keys, - cur_local_commitment_transaction_number: (1 << 48) - 1, - cur_remote_commitment_transaction_number: (1 << 48) - 1, + cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, + cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, value_to_self_msat: channel_value_satoshis * 1000 - push_msat, pending_inbound_htlcs: Vec::new(), pending_outbound_htlcs: Vec::new(), @@ -594,8 +597,8 @@ impl Channel { announce_publicly: their_announce, local_keys: chan_keys, - cur_local_commitment_transaction_number: (1 << 48) - 1, - cur_remote_commitment_transaction_number: (1 << 48) - 1, + cur_local_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, + cur_remote_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, value_to_self_msat: msg.push_msat, pending_inbound_htlcs: Vec::new(), pending_outbound_htlcs: Vec::new(), @@ -693,7 +696,7 @@ impl Channel { /// which peer generated this transaction and "to whom" this transaction flows. #[inline] fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool) -> (Transaction, Vec) { - let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (0xffffffffffff - commitment_number); + let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number); let txins = { let mut ins: Vec = Vec::new(); @@ -1303,7 +1306,9 @@ impl Channel { // channel. return Err(HandleError{err: "Received funding_created after we got the channel!", action: Some(msgs::ErrorAction::SendErrorMessage {msg: msgs::ErrorMessage {channel_id: self.channel_id, data: "Received funding_created after we got the channel!".to_string()}})}); } - if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 1 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 { + if self.channel_monitor.get_min_seen_secret() != (1 << 48) || + self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || + self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); } @@ -1342,7 +1347,9 @@ impl Channel { if self.channel_state != ChannelState::FundingCreated as u32 { return Err(HandleError{err: "Received funding_signed in strange state!", action: None}); } - if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 2 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 { + if self.channel_monitor.get_min_seen_secret() != (1 << 48) || + self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER - 1 || + self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); } @@ -1375,8 +1382,9 @@ impl Channel { self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK); self.channel_update_count += 1; } else if self.channel_state & (ChannelState::ChannelFunded as u32) != 0 && - self.cur_local_commitment_transaction_number == (1 << 48) - 2 && - self.cur_remote_commitment_transaction_number == (1 << 48) - 2 { + // Note that funding_signed/funding_created will have decremented both by 1! + self.cur_local_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 && + self.cur_remote_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 { if self.their_cur_commitment_point != Some(msg.next_per_commitment_point) { return Err(HandleError{err: "Peer sent a reconnect funding_locked with a different point", action: None}); } @@ -1826,7 +1834,9 @@ impl Channel { /// HTLCs that we intended to add but haven't as we were waiting on a remote revoke. /// Returns the set of PendingHTLCStatuses from remote uncommitted HTLCs (which we're /// implicitly dropping) and the payment_hashes of HTLCs we tried to add but are dropping. - pub fn remove_uncommitted_htlcs(&mut self) -> Vec<(HTLCSource, [u8; 32])> { + /// No further message handling calls may be made until a channel_reestablish dance has + /// completed. + pub fn remove_uncommitted_htlcs_and_mark_paused(&mut self) -> Vec<(HTLCSource, [u8; 32])> { let mut outbound_drops = Vec::new(); assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); @@ -1835,12 +1845,14 @@ impl Channel { return outbound_drops; } + let mut inbound_drop_count = 0; self.pending_inbound_htlcs.retain(|htlc| { match htlc.state { InboundHTLCState::RemoteAnnounced => { // They sent us an update_add_htlc but we never got the commitment_signed. // We'll tell them what commitment_signed we're expecting next and they'll drop // this HTLC accordingly + inbound_drop_count += 1; false }, InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => { @@ -1879,6 +1891,8 @@ impl Channel { &HTLCUpdateAwaitingACK::ClaimHTLC {..} | &HTLCUpdateAwaitingACK::FailHTLC {..} => true, } }); + self.channel_state |= ChannelState::PeerDisconnected as u32; + log_debug!(self, "Peer disconnection resulted in {} remote-announced HTLC drops and {} waiting-to-locally-announced HTLC drops on channel {}", outbound_drops.len(), inbound_drop_count, log_bytes!(self.channel_id())); outbound_drops } @@ -1895,6 +1909,85 @@ impl Channel { Ok(()) } + /// May panic if some calls other than message-handling calls (which will all Err immediately) + /// have been called between remove_uncommitted_htlcs_and_mark_paused and this call. + pub fn channel_reestablish(&mut self, msg: &msgs::ChannelReestablish) -> Result<(Option, Option, Option, Option), HandleError> { + if self.channel_state & (ChannelState::PeerDisconnected as u32) == 0 { + return Err(HandleError{err: "Peer sent a loose channel_reestablish not after reconnect", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent a loose channel_reestablish not after reconnect".to_string(), channel_id: msg.channel_id}})}); + } + + if msg.next_local_commitment_number == 0 || msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || + msg.next_remote_commitment_number == 0 || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER { + return Err(HandleError{err: "Peer send garbage channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer send garbage channel_reestablish".to_string(), channel_id: msg.channel_id}})}); + } + + // Go ahead and unmark PeerDisconnected as various calls we may make check for it (and all + // remaining cases either succeed or ErrorMessage-fail). + self.channel_state &= !(ChannelState::PeerDisconnected as u32); + + let mut required_revoke = None; + if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number { + // Remote isn't waiting on any RevokeAndACK from us! + // Note that if we need to repeat our FundingLocked we'll do that in the next if block. + } else if msg.next_remote_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number { + let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number)); + let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 2); + required_revoke = Some(msgs::RevokeAndACK { + channel_id: self.channel_id, + per_commitment_secret, + next_per_commitment_point, + }); + } else { + return Err(HandleError{err: "Peer attempted to reestablish channel with a very old local commitment transaction", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer attempted to reestablish channel with a very old remote commitment transaction".to_string(), channel_id: msg.channel_id}})}); + } + + if msg.next_local_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number { + if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number { + log_debug!(self, "Reconnected channel {} with no lost commitment txn", log_bytes!(self.channel_id())); + if msg.next_local_commitment_number == 1 && msg.next_remote_commitment_number == 1 { + 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 { + channel_id: self.channel_id(), + next_per_commitment_point: next_per_commitment_point, + }), None, None, None)); + } + } + + if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 { + // We're up-to-date and not waiting on a remote revoke (if we are our + // channel_reestablish should result in them sending a revoke_and_ack), but we may + // have received some updates while we were disconnected. Free the holding cell + // now! + match self.free_holding_cell_htlcs() { + Err(e) => { + if let &Some(msgs::ErrorAction::DisconnectPeer{msg: Some(_)}) = &e.action { + } else if let &Some(msgs::ErrorAction::SendErrorMessage{msg: _}) = &e.action { + } else { + panic!("Got non-channel-failing result from free_holding_cell_htlcs"); + } + return Err(e); + }, + Ok(Some((commitment_update, channel_monitor))) => return Ok((None, required_revoke, Some(commitment_update), Some(channel_monitor))), + Ok(None) => return Ok((None, required_revoke, None, None)), + } + } else { + return Ok((None, required_revoke, None, None)); + } + } else if msg.next_local_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_remote_commitment_transaction_number { + return Ok((None, required_revoke, + Some(msgs::CommitmentUpdate { + update_add_htlcs: Vec::new(), + update_fulfill_htlcs: Vec::new(), + update_fail_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), + commitment_signed: self.send_commitment_no_state_update().expect("It looks like we failed to re-generate a commitment_signed we had previously sent?").0, + }), None)); + } else { + return Err(HandleError{err: "Peer attempted to reestablish channel with a very old remote commitment transaction", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer attempted to reestablish channel with a very old remote commitment transaction".to_string(), channel_id: msg.channel_id}})}); + } + } + pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option, Option, Vec<(HTLCSource, [u8; 32])>), HandleError> { if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { return Err(HandleError{err: "Peer sent shutdown when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent shutdown when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})}); @@ -2167,6 +2260,11 @@ impl Channel { res as u32 } + /// Returns true if we've ever received a message from the remote end for this Channel + pub fn have_received_message(&self) -> bool { + self.channel_state > (ChannelState::OurInitSent as u32) + } + /// 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 { @@ -2301,7 +2399,7 @@ impl Channel { panic!("Cannot generate an open_channel after we've moved forward"); } - if self.cur_local_commitment_transaction_number != (1 << 48) - 1 { + if self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { panic!("Tried to send an open_channel for a channel that has already advanced"); } @@ -2337,7 +2435,7 @@ impl Channel { if self.channel_state != (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32) { panic!("Tried to send accept_channel after channel had moved forward"); } - if self.cur_local_commitment_transaction_number != (1 << 48) - 1 { + if self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { panic!("Tried to send an accept_channel for a channel that has already advanced"); } @@ -2386,7 +2484,9 @@ impl Channel { if self.channel_state != (ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32) { panic!("Tried to get a funding_created messsage at a time other than immediately after initial handshake completion (or tried to get funding_created twice)"); } - if self.channel_monitor.get_min_seen_secret() != (1 << 48) || self.cur_remote_commitment_transaction_number != (1 << 48) - 1 || self.cur_local_commitment_transaction_number != (1 << 48) - 1 { + if self.channel_monitor.get_min_seen_secret() != (1 << 48) || + self.cur_remote_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || + self.cur_local_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); } @@ -2457,6 +2557,18 @@ impl Channel { Ok((msg, sig)) } + /// May panic if called on a channel that wasn't immediately-previously + /// self.remove_uncommitted_htlcs_and_mark_paused()'d + pub fn get_channel_reestablish(&self) -> msgs::ChannelReestablish { + assert_eq!(self.channel_state & ChannelState::PeerDisconnected as u32, ChannelState::PeerDisconnected as u32); + msgs::ChannelReestablish { + channel_id: self.channel_id(), + next_local_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number, + next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number, + data_loss_protect: None, + } + } + // Send stuff to our remote peers: