Merge pull request #1163 from TheBlueMatt/2021-11-support-insecure-counterparty
[rust-lightning] / lightning / src / chain / channelmonitor.rs
index a7506acb4dc5ba6bb8ed8db88731b9f51fa6e57c..1699e4827236c89ba6e1dc6fef6b7ff726db6366 100644 (file)
@@ -146,9 +146,16 @@ pub enum MonitorEvent {
                /// same [`ChannelMonitor`] have been applied and persisted.
                monitor_update_id: u64,
        },
+
+       /// Indicates a [`ChannelMonitor`] update has failed. See
+       /// [`ChannelMonitorUpdateErr::PermanentFailure`] for more information on how this is used.
+       ///
+       /// [`ChannelMonitorUpdateErr::PermanentFailure`]: super::ChannelMonitorUpdateErr::PermanentFailure
+       UpdateFailed(OutPoint),
 }
 impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
-       // Note that UpdateCompleted is currently never serialized to disk as it is generated only in ChainMonitor
+       // Note that UpdateCompleted and UpdateFailed are currently never serialized to disk as they are
+       // generated only in ChainMonitor
        (0, UpdateCompleted) => {
                (0, funding_txo, required),
                (2, monitor_update_id, required),
@@ -156,6 +163,7 @@ impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
 ;
        (2, HTLCEvent),
        (4, CommitmentTxConfirmed),
+       (6, UpdateFailed),
 );
 
 /// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
@@ -217,8 +225,6 @@ pub const ANTI_REORG_DELAY: u32 = 6;
 ///    fail this HTLC,
 /// 2) if we receive an HTLC within this many blocks of its expiry (plus one to avoid a race
 ///    condition with the above), we will fail this HTLC without telling the user we received it,
-/// 3) if we are waiting on a connection or a channel state update to send an HTLC to a peer, and
-///    that HTLC expires within this many blocks, we will simply fail the HTLC instead.
 ///
 /// (1) is all about protecting us - we need enough time to update the channel state before we hit
 /// CLTV_CLAIM_BUFFER, at which point we'd go on chain to claim the HTLC with the preimage.
@@ -226,9 +232,6 @@ pub const ANTI_REORG_DELAY: u32 = 6;
 /// (2) is the same, but with an additional buffer to avoid accepting an HTLC which is immediately
 /// in a race condition between the user connecting a block (which would fail it) and the user
 /// providing us the preimage (which would claim it).
-///
-/// (3) is about our counterparty - we don't want to relay an HTLC to a counterparty when they may
-/// end up force-closing the channel on us to claim it.
 pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS;
 
 // TODO(devrandom) replace this with HolderCommitmentTransaction
@@ -649,7 +652,17 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
 
        payment_preimages: HashMap<PaymentHash, PaymentPreimage>,
 
+       // Note that `MonitorEvent`s MUST NOT be generated during update processing, only generated
+       // during chain data processing. This prevents a race in `ChainMonitor::update_channel` (and
+       // presumably user implementations thereof as well) where we update the in-memory channel
+       // object, then before the persistence finishes (as it's all under a read-lock), we return
+       // pending events to the user or to the relevant `ChannelManager`. Then, on reload, we'll have
+       // the pre-event state here, but have processed the event in the `ChannelManager`.
+       // Note that because the `event_lock` in `ChainMonitor` is only taken in
+       // block/transaction-connected events and *not* during block/transaction-disconnected events,
+       // we further MUST NOT generate events during block/transaction-disconnection.
        pending_monitor_events: Vec<MonitorEvent>,
+
        pending_events: Vec<Event>,
 
        // Used to track on-chain events (i.e., transactions part of channels confirmed on chain) on
@@ -1497,6 +1510,101 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
 
                res
        }
+
+       /// Gets the set of outbound HTLCs which are pending resolution in this channel.
+       /// This is used to reconstruct pending outbound payments on restart in the ChannelManager.
+       pub(crate) fn get_pending_outbound_htlcs(&self) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
+               let mut res = HashMap::new();
+               let us = self.inner.lock().unwrap();
+
+               macro_rules! walk_htlcs {
+                       ($holder_commitment: expr, $htlc_iter: expr) => {
+                               for (htlc, source) in $htlc_iter {
+                                       if us.htlcs_resolved_on_chain.iter().any(|v| Some(v.input_idx) == htlc.transaction_output_index) {
+                                               // We should assert that funding_spend_confirmed is_some() here, but we
+                                               // have some unit tests which violate HTLC transaction CSVs entirely and
+                                               // would fail.
+                                               // TODO: Once tests all connect transactions at consensus-valid times, we
+                                               // should assert here like we do in `get_claimable_balances`.
+                                       } else if htlc.offered == $holder_commitment {
+                                               // If the payment was outbound, check if there's an HTLCUpdate
+                                               // indicating we have spent this HTLC with a timeout, claiming it back
+                                               // and awaiting confirmations on it.
+                                               let htlc_update_confd = us.onchain_events_awaiting_threshold_conf.iter().any(|event| {
+                                                       if let OnchainEvent::HTLCUpdate { input_idx: Some(input_idx), .. } = event.event {
+                                                               // If the HTLC was timed out, we wait for ANTI_REORG_DELAY blocks
+                                                               // before considering it "no longer pending" - this matches when we
+                                                               // provide the ChannelManager an HTLC failure event.
+                                                               Some(input_idx) == htlc.transaction_output_index &&
+                                                                       us.best_block.height() >= event.height + ANTI_REORG_DELAY - 1
+                                                       } else if let OnchainEvent::HTLCSpendConfirmation { input_idx, .. } = event.event {
+                                                               // If the HTLC was fulfilled with a preimage, we consider the HTLC
+                                                               // immediately non-pending, matching when we provide ChannelManager
+                                                               // the preimage.
+                                                               Some(input_idx) == htlc.transaction_output_index
+                                                       } else { false }
+                                               });
+                                               if !htlc_update_confd {
+                                                       res.insert(source.clone(), htlc.clone());
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // We're only concerned with the confirmation count of HTLC transactions, and don't
+               // actually care how many confirmations a commitment transaction may or may not have. Thus,
+               // we look for either a FundingSpendConfirmation event or a funding_spend_confirmed.
+               let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
+                       us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
+                               if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
+                                       Some(event.txid)
+                               } else { None }
+                       })
+               });
+               if let Some(txid) = confirmed_txid {
+                       if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid {
+                               walk_htlcs!(false, us.counterparty_claimable_outpoints.get(&txid).unwrap().iter().filter_map(|(a, b)| {
+                                       if let &Some(ref source) = b {
+                                               Some((a, &**source))
+                                       } else { None }
+                               }));
+                       } else if txid == us.current_holder_commitment_tx.txid {
+                               walk_htlcs!(true, us.current_holder_commitment_tx.htlc_outputs.iter().filter_map(|(a, _, c)| {
+                                       if let Some(source) = c { Some((a, source)) } else { None }
+                               }));
+                       } else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx {
+                               if txid == prev_commitment.txid {
+                                       walk_htlcs!(true, prev_commitment.htlc_outputs.iter().filter_map(|(a, _, c)| {
+                                               if let Some(source) = c { Some((a, source)) } else { None }
+                                       }));
+                               }
+                       }
+               } else {
+                       // If we have not seen a commitment transaction on-chain (ie the channel is not yet
+                       // closed), just examine the available counterparty commitment transactions. See docs
+                       // on `fail_unbroadcast_htlcs`, below, for justification.
+                       macro_rules! walk_counterparty_commitment {
+                               ($txid: expr) => {
+                                       if let Some(ref latest_outpoints) = us.counterparty_claimable_outpoints.get($txid) {
+                                               for &(ref htlc, ref source_option) in latest_outpoints.iter() {
+                                                       if let &Some(ref source) = source_option {
+                                                               res.insert((**source).clone(), htlc.clone());
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if let Some(ref txid) = us.current_counterparty_commitment_txid {
+                               walk_counterparty_commitment!(txid);
+                       }
+                       if let Some(ref txid) = us.prev_counterparty_commitment_txid {
+                               walk_counterparty_commitment!(txid);
+                       }
+               }
+
+               res
+       }
 }
 
 /// Compares a broadcasted commitment transaction's HTLCs with those in the latest state,
@@ -2247,7 +2355,8 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
                                let prevout = &tx.input[0].previous_output;
                                if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 {
                                        let mut balance_spendable_csv = None;
-                                       log_info!(logger, "Channel closed by funding output spend in txid {}.", log_bytes!(tx.txid()));
+                                       log_info!(logger, "Channel {} closed by funding output spend in txid {}.",
+                                               log_bytes!(self.funding_info.0.to_channel_id()), tx.txid());
                                        if (tx.input[0].sequence >> 8*3) as u8 == 0x80 && (tx.lock_time >> 8*3) as u8 == 0x20 {
                                                let (mut new_outpoints, new_outputs) = self.check_spend_counterparty_transaction(&tx, height, &logger);
                                                if !new_outputs.1.is_empty() {
@@ -3272,6 +3381,7 @@ mod tests {
                                selected_contest_delay: 67,
                        }),
                        funding_outpoint: Some(funding_outpoint),
+                       opt_anchors: None,
                };
                // Prune with one old state and a holder commitment tx holding a few overlaps with the
                // old state.
@@ -3337,7 +3447,7 @@ mod tests {
                let mut sum_actual_sigs = 0;
 
                macro_rules! sign_input {
-                       ($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr) => {
+                       ($sighash_parts: expr, $idx: expr, $amount: expr, $weight: expr, $sum_actual_sigs: expr, $opt_anchors: expr) => {
                                let htlc = HTLCOutputInCommitment {
                                        offered: if *$weight == WEIGHT_REVOKED_OFFERED_HTLC || *$weight == WEIGHT_OFFERED_HTLC { true } else { false },
                                        amount_msat: 0,
@@ -3345,7 +3455,7 @@ mod tests {
                                        payment_hash: PaymentHash([1; 32]),
                                        transaction_output_index: Some($idx as u32),
                                };
-                               let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &pubkey, &pubkey, &pubkey) };
+                               let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &pubkey, &pubkey, &pubkey) };
                                let sighash = hash_to_message!(&$sighash_parts.signature_hash($idx, &redeem_script, $amount, SigHashType::All)[..]);
                                let sig = secp_ctx.sign(&sighash, &privkey);
                                $sighash_parts.access_witness($idx).push(sig.serialize_der().to_vec());
@@ -3393,7 +3503,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }
@@ -3419,7 +3529,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }
@@ -3443,7 +3553,7 @@ mod tests {
                {
                        let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx);
                        for (idx, inp) in inputs_weight.iter().enumerate() {
-                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
+                               sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, false);
                                inputs_total_weight += inp;
                        }
                }