From 7e255b5cf5256638b5ec6e507c68d9cfa0ba2047 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sun, 29 Jul 2018 01:59:42 -0400 Subject: [PATCH] Handle invalid funding tx in channelmanager --- src/ln/channel.rs | 14 +++++++++----- src/ln/channelmanager.rs | 13 ++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 3a442091c..acee06409 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::{HandleError, MsgEncodable}; +use ln::msgs::{ErrorAction, HandleError, MsgEncodable}; use ln::channelmonitor::ChannelMonitor; use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason}; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; @@ -1916,7 +1916,10 @@ impl Channel { /// 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. - pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Option { + /// 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> { let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK); if self.funding_tx_confirmations > 0 { if header.bitcoin_hash() != self.last_block_connected { @@ -1940,10 +1943,10 @@ impl Channel { //a protocol oversight, but I assume I'm just missing something. 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).unwrap(); - return Some(msgs::FundingLocked { + return Ok(Some(msgs::FundingLocked { channel_id: self.channel_id, next_per_commitment_point: next_per_commitment_point, - }); + })); } } } @@ -1955,6 +1958,7 @@ impl Channel { tx.output[txo_idx].value != self.channel_value_satoshis { 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})}); } else { self.funding_tx_confirmations = 1; self.short_channel_id = Some(((height as u64) << (5*8)) | @@ -1964,7 +1968,7 @@ impl Channel { } } } - None + Ok(None) } /// Called by channelmanager based on chain blocks being disconnected. diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 6c349fd0e..f39d0c093 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -1141,7 +1141,8 @@ impl ChainListener for ChannelManager { let channel_state = channel_lock.borrow_parts(); let short_to_id = channel_state.short_to_id; channel_state.by_id.retain(|_, channel| { - if let Some(funding_locked) = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched) { + let chan_res = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched); + if let Ok(Some(funding_locked)) = chan_res { let announcement_sigs = match self.get_announcement_sigs(channel) { Ok(res) => res, Err(_e) => { @@ -1155,6 +1156,16 @@ impl ChainListener for ChannelManager { announcement_sigs: announcement_sigs }); short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id()); + } else if let Err(e) = chan_res { + if let Some(msgs::ErrorAction::DisconnectPeer { msg }) = e.action { + new_events.push(events::Event::DisconnectPeer { + node_id: channel.get_their_node_id(), + msg: msg + }); + } else { unreachable!(); } + if channel.is_shutdown() { + return false; + } } if let Some(funding_txo) = channel.get_funding_txo() { for tx in txn_matched { -- 2.39.5