X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=296d97c164ea967839fa2f6ec93ab66f215f56fe;hb=23c2cef5f42c201ed5f87edeffaab77490d7b427;hp=e0fdcaf9080627a3dae94786adadc080707aca82;hpb=6969fc997bd18d21c5a25fae34bc1eb123bf512b;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index e0fdcaf9..296d97c1 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -13,7 +13,7 @@ use secp256k1; use crypto::digest::Digest; use ln::msgs; -use ln::msgs::{DecodeError, ErrorAction, HandleError}; +use ln::msgs::DecodeError; use ln::channelmonitor::ChannelMonitor; use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder}; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; @@ -373,15 +373,6 @@ pub(super) enum ChannelError { Close(&'static str), } -macro_rules! secp_call { - ( $res: expr, $err: expr, $chan_id: expr ) => { - match $res { - Ok(key) => key, - Err(_) => return Err(HandleError {err: $err, action: Some(msgs::ErrorAction::SendErrorMessage {msg: msgs::ErrorMessage {channel_id: $chan_id, data: $err.to_string()}})}) - } - }; -} - macro_rules! secp_check { ($res: expr, $err: expr) => { match $res { @@ -1013,6 +1004,7 @@ impl Channel { #[inline] /// Creates a set of keys for build_commitment_transaction to generate a transaction which we /// will sign and send to our counterparty. + /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) fn build_remote_transaction_keys(&self) -> Result { //TODO: Ensure that the payment_key derived here ends up in the library users' wallet as we //may see payments to it! @@ -1528,40 +1520,40 @@ impl Channel { (self.pending_outbound_htlcs.len() as u32, htlc_outbound_value_msat) } - pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), HandleError> { + pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) { - return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None}); + return Err(ChannelError::Close("Got add HTLC message when channel was not in an operational state")); } if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { - return Err(HandleError{err: "Peer sent update_add_htlc when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent update_add_htlc when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})}); + return Err(ChannelError::Close("Peer sent update_add_htlc when we needed a channel_reestablish")); } if msg.amount_msat > self.channel_value_satoshis * 1000 { - return Err(HandleError{err: "Remote side tried to send more than the total value of the channel", action: None}); + return Err(ChannelError::Close("Remote side tried to send more than the total value of the channel")); } if msg.amount_msat < self.our_htlc_minimum_msat { - return Err(HandleError{err: "Remote side tried to send less than our minimum HTLC value", action: None}); + return Err(ChannelError::Close("Remote side tried to send less than our minimum HTLC value")); } let (inbound_htlc_count, htlc_inbound_value_msat) = self.get_inbound_pending_htlc_stats(); if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 { - return Err(HandleError{err: "Remote tried to push more than our max accepted HTLCs", action: None}); + return Err(ChannelError::Close("Remote tried to push more than our max accepted HTLCs")); } //TODO: Spec is unclear if this is per-direction or in total (I assume per direction): // Check our_max_htlc_value_in_flight_msat if htlc_inbound_value_msat + msg.amount_msat > Channel::get_our_max_htlc_value_in_flight_msat(self.channel_value_satoshis) { - return Err(HandleError{err: "Remote HTLC add would put them over their max HTLC value in flight", action: None}); + return Err(ChannelError::Close("Remote HTLC add would put them over their max HTLC value in flight")); } // Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet // the reserve_satoshis we told them to always have as direct payment so that they lose // something if we punish them for broadcasting an old state). if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 { - return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", action: None}); + return Err(ChannelError::Close("Remote HTLC add would put them over their reserve value")); } if self.next_remote_htlc_id != msg.htlc_id { - return Err(HandleError{err: "Remote skipped HTLC ID", action: None}); + return Err(ChannelError::Close("Remote skipped HTLC ID")); } if msg.cltv_expiry >= 500000000 { - return Err(HandleError{err: "Remote provided CLTV expiry in seconds instead of block height", action: None}); + 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? @@ -1613,7 +1605,7 @@ impl Channel { Err(ChannelError::Close("Remote tried to fulfill/fail an HTLC we couldn't find")) } - pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<&HTLCSource, ChannelError> { + pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Close("Got fulfill HTLC message when channel was not in an operational state")); } @@ -1626,10 +1618,10 @@ impl Channel { let mut payment_hash = [0; 32]; sha.result(&mut payment_hash); - self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None) + self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None).map(|source| source.clone()) } - pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, ChannelError> { + pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Close("Got fail HTLC message when channel was not in an operational state")); } @@ -1637,10 +1629,11 @@ impl Channel { return Err(ChannelError::Close("Peer sent update_fail_htlc when we needed a channel_reestablish")); } - self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason)) + self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?; + Ok(()) } - pub fn update_fail_malformed_htlc<'a>(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<&HTLCSource, ChannelError> { + pub fn update_fail_malformed_htlc<'a>(&mut self, msg: &msgs::UpdateFailMalformedHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Close("Got fail malformed HTLC message when channel was not in an operational state")); } @@ -1648,7 +1641,8 @@ impl Channel { return Err(ChannelError::Close("Peer sent update_fail_malformed_htlc when we needed a channel_reestablish")); } - self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason)) + self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?; + Ok(()) } pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned, fee_estimator: &FeeEstimator) -> Result<(msgs::RevokeAndACK, Option, Option, ChannelMonitor), ChannelError> { @@ -2295,7 +2289,8 @@ impl Channel { return Err(ChannelError::Close("Peer sent a loose channel_reestablish not after reconnect")); } - if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER { + if msg.next_local_commitment_number >= INITIAL_COMMITMENT_NUMBER || msg.next_remote_commitment_number >= INITIAL_COMMITMENT_NUMBER || + msg.next_local_commitment_number == 0 { return Err(ChannelError::Close("Peer sent a garbage channel_reestablish")); } @@ -2310,15 +2305,15 @@ impl Channel { }) } else { None }; - if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) == ChannelState::FundingSent as u32 { - // Short circuit the whole handler as there is nothing we can resend them - return Ok((None, None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg)); - } - - if msg.next_local_commitment_number == 0 || msg.next_remote_commitment_number == 0 { - if self.channel_state & (ChannelState::FundingSent as u32) != ChannelState::FundingSent as u32 { - return Err(ChannelError::Close("Peer sent a pre-funding channel_reestablish after we exchanged funding_locked")); + if self.channel_state & (ChannelState::FundingSent as u32) == ChannelState::FundingSent as u32 { + if self.channel_state & ChannelState::OurFundingLocked as u32 == 0 { + if msg.next_remote_commitment_number != 0 { + return Err(ChannelError::Close("Peer claimed they saw a revoke_and_ack but we haven't sent funding_locked yet")); + } + // Short circuit the whole handler as there is nothing we can resend them + return Ok((None, None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg)); } + // We have OurFundingLocked set! 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); @@ -2328,11 +2323,11 @@ impl Channel { }), None, None, None, RAACommitmentOrder::CommitmentFirst, shutdown_msg)); } - let required_revoke = if msg.next_remote_commitment_number == INITIAL_COMMITMENT_NUMBER - self.cur_local_commitment_transaction_number { + let required_revoke = if msg.next_remote_commitment_number + 1 == 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. None - } else if msg.next_remote_commitment_number == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number { + } else if msg.next_remote_commitment_number + 1 == (INITIAL_COMMITMENT_NUMBER - 1) - self.cur_local_commitment_transaction_number { if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) != 0 { self.monitor_pending_revoke_and_ack = true; None @@ -2508,24 +2503,24 @@ impl Channel { Ok((our_shutdown, self.maybe_propose_first_closing_signed(fee_estimator), dropped_outbound_htlcs)) } - pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option, Option), HandleError> { + pub fn closing_signed(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::ClosingSigned) -> Result<(Option, Option), ChannelError> { if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK { - return Err(HandleError{err: "Remote end sent us a closing_signed before both sides provided a shutdown", action: None}); + return Err(ChannelError::Close("Remote end sent us a closing_signed before both sides provided a shutdown")); } if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { - return Err(HandleError{err: "Peer sent closing_signed when we needed a channel_reestablish", action: Some(msgs::ErrorAction::SendErrorMessage{msg: msgs::ErrorMessage{data: "Peer sent closing_signed when we needed a channel_reestablish".to_string(), channel_id: msg.channel_id}})}); + return Err(ChannelError::Close("Peer sent closing_signed when we needed a channel_reestablish")); } if !self.pending_inbound_htlcs.is_empty() || !self.pending_outbound_htlcs.is_empty() { - return Err(HandleError{err: "Remote end sent us a closing_signed while there were still pending HTLCs", action: None}); + return Err(ChannelError::Close("Remote end sent us a closing_signed while there were still pending HTLCs")); } if msg.fee_satoshis > 21000000 * 10000000 { //this is required to stop potential overflow in build_closing_transaction - return Err(HandleError{err: "Remote tried to send us a closing tx with > 21 million BTC fee", action: None}); + return Err(ChannelError::Close("Remote tried to send us a closing tx with > 21 million BTC fee")); } let funding_redeemscript = self.get_funding_redeemscript(); let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, false); if used_total_fee != msg.fee_satoshis { - return Err(HandleError{err: "Remote sent us a closing_signed with a fee greater than the value they can claim", action: None}); + return Err(ChannelError::Close("Remote sent us a closing_signed with a fee greater than the value they can claim")); } let mut sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap(); @@ -2536,7 +2531,7 @@ impl Channel { // limits, so check for that case by re-checking the signature here. closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0; sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap(); - secp_call!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid closing tx signature from peer", self.channel_id()); + secp_check!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid closing tx signature from peer"); }, }; @@ -2570,7 +2565,7 @@ impl Channel { if proposed_sat_per_kw > our_max_feerate { if let Some((last_feerate, _)) = self.last_sent_closing_fee { if our_max_feerate <= last_feerate { - return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate", action: None}); + return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something higher than our Normal feerate")); } } propose_new_feerate!(our_max_feerate); @@ -2580,7 +2575,7 @@ impl Channel { if proposed_sat_per_kw < our_min_feerate { if let Some((last_feerate, _)) = self.last_sent_closing_fee { if our_min_feerate >= last_feerate { - return Err(HandleError{err: "Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate", action: None}); + return Err(ChannelError::Close("Unable to come to consensus about closing feerate, remote wanted something lower than our Background feerate")); } } propose_new_feerate!(our_min_feerate); @@ -2780,7 +2775,7 @@ impl Channel { /// 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. /// 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, HandleError> { + pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result, msgs::ErrorMessage> { let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); if header.bitcoin_hash() != self.last_block_connected { self.last_block_connected = header.bitcoin_hash(); @@ -2840,7 +2835,10 @@ impl Channel { } self.channel_state = ChannelState::ShutdownComplete as u32; self.channel_update_count += 1; - return Err(HandleError{err: "funding tx had wrong script/value", action: Some(ErrorAction::DisconnectPeer{msg: None})}); + return Err(msgs::ErrorMessage { + channel_id: self.channel_id(), + data: "funding tx had wrong script/value".to_owned() + }); } else { if self.channel_outbound { for input in tx.input.iter() { @@ -2953,6 +2951,7 @@ impl Channel { } } + /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), ChannelError> { let funding_script = self.get_funding_redeemscript(); @@ -2970,6 +2969,7 @@ impl Channel { /// or if called on an inbound 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) -> Result<(msgs::FundingCreated, ChannelMonitor), ChannelError> { if !self.channel_outbound { panic!("Tried to create outbound funding_created message on an inbound channel!"); @@ -3054,11 +3054,27 @@ impl Channel { /// 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); + assert_ne!(self.cur_remote_commitment_transaction_number, INITIAL_COMMITMENT_NUMBER); msgs::ChannelReestablish { channel_id: self.channel_id(), + // The protocol has two different commitment number concepts - the "commitment + // transaction number", which starts from 0 and counts up, and the "revocation key + // index" which starts at INITIAL_COMMITMENT_NUMBER and counts down. We track + // commitment transaction numbers by the index which will be used to reveal the + // revocation key for that commitment transaction, which means we have to convert them + // to protocol-level commitment numbers here... + + // next_local_commitment_number is the next commitment_signed number we expect to + // receive (indicating if they need to resend one that we missed). 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 - - if self.channel_state & (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) == (ChannelState::FundingSent as u32) { 1 } else { 0 }, + // We have to set next_remote_commitment_number to the next revoke_and_ack we expect to + // receive, however we track it by the next commitment number for a remote transaction + // (which is one further, as they always revoke previous commitment transaction, not + // the one we send) so we have to decrement by 1. Note that if + // cur_remote_commitment_transaction_number is INITIAL_COMMITMENT_NUMBER we will have + // dropped this channel on disconnect as it hasn't yet reached FundingSent so we can't + // overflow here. + next_remote_commitment_number: INITIAL_COMMITMENT_NUMBER - self.cur_remote_commitment_transaction_number - 1, data_loss_protect: None, } } @@ -3160,7 +3176,7 @@ impl Channel { } /// Creates a signed commitment transaction to send to the remote peer. - /// Always returns a Channel-failing HandleError::action if an immediately-preceding (read: the + /// Always returns a ChannelError::Close if an immediately-preceding (read: the /// last call to this Channel) send_htlc returned Ok(Some(_)) and there is an Err. /// May panic if called except immediately after a successful, Ok(Some(_))-returning send_htlc. pub fn send_commitment(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), ChannelError> { @@ -3902,6 +3918,7 @@ mod tests { } fn get_channel_keys(&self, _inbound: bool) -> ChannelKeys { self.chan_keys.clone() } + fn get_session_key(&self) -> SecretKey { panic!(); } } #[test]