Merge pull request #269 from TheBlueMatt/2018-12-198-review
[rust-lightning] / src / ln / channelmonitor.rs
index b1e7df29cddfa5bcd3a2394453310a97dbb1e176..beb5a51047b5872faf1622e095dc20d56734d0d1 100644 (file)
@@ -295,6 +295,11 @@ pub(crate) const CLTV_CLAIM_BUFFER: u32 = 6;
 /// network and done a full update_fail_htlc/commitment_signed dance (+ we've updated all our
 /// copies of ChannelMonitors, including watchtowers).
 pub(crate) const HTLC_FAIL_TIMEOUT_BLOCKS: u32 = 3;
+/// Number of blocks we wait on seeing a confirmed HTLC-Timeout or previous revoked commitment
+/// transaction before we fail corresponding inbound HTLCs. This prevents us from failing backwards
+/// and then getting a reorg resulting in us losing money.
+//TODO: We currently dont actually use this...we should
+pub(crate) const HTLC_FAIL_ANTI_REORG_DELAY: u32 = 6;
 
 #[derive(Clone, PartialEq)]
 enum Storage {
@@ -1178,6 +1183,7 @@ impl ChannelMonitor {
 
                        if !inputs.is_empty() || !txn_to_broadcast.is_empty() { // ie we're confident this is actually ours
                                // We're definitely a remote commitment transaction!
+                               log_trace!(self, "Got broadcast of revoked remote commitment transaction, generating general spend tx with {} inputs and {} other txn to broadcast", inputs.len(), txn_to_broadcast.len());
                                watch_outputs.append(&mut tx.output.clone());
                                self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
                        }
@@ -1215,6 +1221,7 @@ impl ChannelMonitor {
                                if let &Some(ref txid) = current_remote_commitment_txid {
                                        if let Some(&(_, ref latest_outpoints)) = self.remote_claimable_outpoints.get(&txid) {
                                                for &(ref payment_hash, ref source, _) in latest_outpoints.iter() {
+                                                       log_trace!(self, "Failing HTLC with payment_hash {} from current remote commitment tx due to broadcast of revoked remote commitment transaction", log_bytes!(payment_hash.0));
                                                        htlc_updated.push(((*source).clone(), None, payment_hash.clone()));
                                                }
                                        }
@@ -1222,6 +1229,7 @@ impl ChannelMonitor {
                                if let &Some(ref txid) = prev_remote_commitment_txid {
                                        if let Some(&(_, ref prev_outpoint)) = self.remote_claimable_outpoints.get(&txid) {
                                                for &(ref payment_hash, ref source, _) in prev_outpoint.iter() {
+                                                       log_trace!(self, "Failing HTLC with payment_hash {} from previous remote commitment tx due to broadcast of revoked remote commitment transaction", log_bytes!(payment_hash.0));
                                                        htlc_updated.push(((*source).clone(), None, payment_hash.clone()));
                                                }
                                        }
@@ -1399,6 +1407,10 @@ impl ChannelMonitor {
                                                output: spend_tx.output[0].clone(),
                                        });
                                        txn_to_broadcast.push(spend_tx);
+
+                                       // TODO: We need to fail back HTLCs that were't included in the broadcast
+                                       // commitment transaction, either because they didn't meet dust or because a
+                                       // stale (but not yet revoked) commitment transaction was broadcast!
                                }
                        }
                }
@@ -1570,6 +1582,9 @@ impl ChannelMonitor {
        /// Should not be used if check_spend_revoked_transaction succeeds.
        fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec<Transaction>, Vec<SpendableOutputDescriptor>, (Sha256dHash, Vec<TxOut>)) {
                let commitment_txid = tx.txid();
+               // TODO: If we find a match here we need to fail back HTLCs that were't included in the
+               // broadcast commitment transaction, either because they didn't meet dust or because they
+               // weren't yet included in our commitment transaction(s).
                if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
                        if local_tx.txid == commitment_txid {
                                match self.key_storage {
@@ -1738,6 +1753,16 @@ impl ChannelMonitor {
        }
 
        pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool {
+               // TODO: We need to consider HTLCs which weren't included in latest local commitment
+               // transaction (or in any of the latest two local commitment transactions). This probably
+               // needs to use the same logic as the revoked-tx-announe logic - checking the last two
+               // remote commitment transactions. This probably has implications for what data we need to
+               // store in local commitment transactions.
+               // TODO: We need to consider HTLCs which were below dust threshold here - while they don't
+               // strictly imply that we need to fail the channel, we need to go ahead and fail them back
+               // to the source, and if we don't fail the channel we will have to ensure that the next
+               // updates that peer sends us are update_fails, failing the channel if not. It's probably
+               // easier to just fail the channel as this case should be rare enough anyway.
                if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
                        for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
                                // For inbound HTLCs which we know the preimage for, we have to ensure we hit the
@@ -1778,16 +1803,17 @@ impl ChannelMonitor {
                        let mut payment_data = None;
 
                        macro_rules! scan_commitment {
-                               ($htlc_outputs: expr, $htlc_sources: expr) => {
+                               ($htlc_outputs: expr, $htlc_sources: expr, $source: expr) => {
                                        for &(ref payment_hash, ref source, ref vout) in $htlc_sources.iter() {
                                                if &Some(input.previous_output.vout) == vout {
+                                                       log_trace!(self, "Input spending {}:{} resolves HTLC with payment hash {} from {}", input.previous_output.txid, input.previous_output.vout, log_bytes!(payment_hash.0), $source);
                                                        payment_data = Some((source.clone(), *payment_hash));
                                                }
                                        }
                                        if payment_data.is_none() {
                                                for htlc_output in $htlc_outputs {
                                                        if input.previous_output.vout == htlc_output.transaction_output_index {
-                                                               log_info!(self, "Inbound HTLC timeout at {} from {} resolved by {}", input.previous_output.vout, input.previous_output.txid, tx.txid());
+                                                               log_info!(self, "Input spending {}:{} in {} resolves inbound HTLC with timeout from {}", input.previous_output.txid, input.previous_output.vout, tx.txid(), $source);
                                                                continue 'outer_loop;
                                                        }
                                                }
@@ -1797,23 +1823,30 @@ impl ChannelMonitor {
 
                        if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx {
                                if input.previous_output.txid == current_local_signed_commitment_tx.txid {
-                                       scan_commitment!(current_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a), current_local_signed_commitment_tx.htlc_sources);
+                                       scan_commitment!(current_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a),
+                                               current_local_signed_commitment_tx.htlc_sources,
+                                               "our latest local commitment tx");
                                }
                        }
                        if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx {
                                if input.previous_output.txid == prev_local_signed_commitment_tx.txid {
-                                       scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a), prev_local_signed_commitment_tx.htlc_sources);
+                                       scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a),
+                                               prev_local_signed_commitment_tx.htlc_sources,
+                                               "our latest local commitment tx");
                                }
                        }
                        if let Some(&(ref htlc_outputs, ref htlc_sources)) = self.remote_claimable_outpoints.get(&input.previous_output.txid) {
-                               scan_commitment!(htlc_outputs, htlc_sources);
+                               scan_commitment!(htlc_outputs, htlc_sources, "remote commitment tx");
                        }
 
                        // If tx isn't solving htlc output from local/remote commitment tx and htlc isn't outbound we don't need
                        // to broadcast solving backward
                        if let Some((source, payment_hash)) = payment_data {
                                let mut payment_preimage = PaymentPreimage([0; 32]);
-                               if input.witness.len() == 5 && input.witness[4].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
+                               if (input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33)
+                                       || (input.witness.len() == 3 && input.witness[2].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33) {
+                                       log_error!(self, "Remote used revocation sig to take a {} HTLC output at index {} from commitment_tx {}", if input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT { "offered" } else { "accepted" }, input.previous_output.vout, input.previous_output.txid);
+                               } else if input.witness.len() == 5 && input.witness[4].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT {
                                        payment_preimage.0.copy_from_slice(&tx.input[0].witness[3]);
                                        htlc_updated.push((source, Some(payment_preimage), payment_hash));
                                } else if input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT {