From 6032099469d03c785c2330029e1bb16171beef31 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 22 Nov 2018 20:50:13 -0500 Subject: [PATCH] Remove remaining uses of HandleError in Channel Err return values This converts block_connected failures to returning the ErrorMessage that needs to be sent directly, since it always results in channel closure and never results in needing to call force_shutdown. It also converts update_add_htlc and closing_signed handlers to ChannelError as the rest of the message handlers. --- src/ln/channel.rs | 58 ++++++++++++++++++---------------------- src/ln/channelmanager.rs | 18 +++++-------- 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/ln/channel.rs b/src/ln/channel.rs index e0fdcaf90..3ddf44afa 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 { @@ -1528,40 +1519,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? @@ -2508,24 +2499,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 +2527,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 +2561,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 +2571,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 +2771,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 +2831,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() { @@ -3160,7 +3154,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> { diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index ddd6b2f21..32dc72f9c 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -169,10 +169,6 @@ impl MsgHandleErrInternal { } } #[inline] - fn from_maybe_close(err: msgs::HandleError) -> Self { - Self { err, needs_channel_force_close: true } - } - #[inline] fn from_no_close(err: msgs::HandleError) -> Self { Self { err, needs_channel_force_close: false } } @@ -1928,7 +1924,7 @@ impl ChannelManager { //TODO: here and below MsgHandleErrInternal, #153 case return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!", msg.channel_id)); } - let (closing_signed, tx) = chan_entry.get_mut().closing_signed(&*self.fee_estimator, &msg).map_err(|e| MsgHandleErrInternal::from_maybe_close(e))?; + let (closing_signed, tx) = chan_entry.get_mut().closing_signed(&*self.fee_estimator, &msg).map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.channel_id))?; if let Some(msg) = closing_signed { channel_state.pending_msg_events.push(events::MessageSendEvent::SendClosingSigned { node_id: their_node_id.clone(), @@ -2005,7 +2001,7 @@ impl ChannelManager { })); } } - chan.update_add_htlc(&msg, pending_forward_info).map_err(|e| MsgHandleErrInternal::from_maybe_close(e)) + chan.update_add_htlc(&msg, pending_forward_info).map_err(|e| MsgHandleErrInternal::from_chan_maybe_close(e, msg.channel_id)) }, None => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel", msg.channel_id)) } @@ -2588,11 +2584,9 @@ impl ChainListener for ChannelManager { } else if let Err(e) = chan_res { pending_msg_events.push(events::MessageSendEvent::HandleError { node_id: channel.get_their_node_id(), - action: e.action, + action: Some(msgs::ErrorAction::SendErrorMessage { msg: e }), }); - if channel.is_shutdown() { - return false; - } + return false; } if let Some(funding_txo) = channel.get_funding_txo() { for tx in txn_matched { @@ -5532,7 +5526,7 @@ mod tests { HandleError{err, .. } => assert_eq!(err, "Remote HTLC add would put them over their reserve value"), } // If we send a garbage message, the channel should get closed, making the rest of this test case fail. - /*assert_eq!(nodes[1].node.list_channels().len(), 1); + assert_eq!(nodes[1].node.list_channels().len(), 1); assert_eq!(nodes[1].node.list_channels().len(), 1); let channel_close_broadcast = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(channel_close_broadcast.len(), 1); @@ -5541,7 +5535,7 @@ mod tests { assert_eq!(msg.contents.flags & 2, 2); }, _ => panic!("Unexpected event"), - }*/ + } return; } } -- 2.39.5