From 7c238476845fcc1115f3115a650f82d7b7f170b1 Mon Sep 17 00:00:00 2001 From: Antoine Riard Date: Fri, 7 Dec 2018 22:09:58 -0500 Subject: [PATCH] Time out AwatingRemoteRAA outgoing HTLCs when we reach cltv_expiry In case of committing out-of-time outgoing HTLCs, we force ourselves to close the channel to avoid remote peer claims on a non-backed HTLC --- lightning/src/ln/channel.rs | 42 ++++++++++++++++++++++-------- lightning/src/ln/channelmanager.rs | 39 +++++++++++++++------------ 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index ac072c0e..f4410943 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; @@ -3154,13 +3154,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 +3263,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. diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 68355222..cbcccb82 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2962,23 +2962,32 @@ impl