Cache to_remote_script if we are fallen-behind
[rust-lightning] / src / ln / channelmonitor.rs
index 2c0a058043d580889acf20f278bc3a9ef8b71219..4d54b6412f1050b52cae8db2b3a28c72297bee0a 100644 (file)
@@ -456,6 +456,10 @@ pub struct ChannelMonitor {
        payment_preimages: HashMap<PaymentHash, PaymentPreimage>,
 
        destination_script: Script,
+       // Thanks to data loss protection, we may be able to claim our non-htlc funds
+       // back, this is the script we have to spend from but we need to
+       // scan every commitment transaction for that
+       to_remote_rescue: Option<(Script, SecretKey)>,
 
        // Used to track outpoint in the process of being claimed by our transactions. We need to scan all transactions
        // for inputs spending this. If height timer (u32) is expired and claim tx hasn't reached enough confirmations
@@ -535,6 +539,7 @@ impl PartialEq for ChannelMonitor {
                        self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
                        self.payment_preimages != other.payment_preimages ||
                        self.destination_script != other.destination_script ||
+                       self.to_remote_rescue != other.to_remote_rescue ||
                        self.our_claim_txn_waiting_first_conf != other.our_claim_txn_waiting_first_conf ||
                        self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf
                {
@@ -585,6 +590,7 @@ impl ChannelMonitor {
 
                        payment_preimages: HashMap::new(),
                        destination_script: destination_script,
+                       to_remote_rescue: None,
 
                        our_claim_txn_waiting_first_conf: HashMap::new(),
 
@@ -763,6 +769,22 @@ impl ChannelMonitor {
                }
        }
 
+       pub(super) fn provide_rescue_remote_commitment_tx_info(&mut self, their_revocation_point: PublicKey) {
+               match self.key_storage {
+                       Storage::Local { ref payment_base_key, .. } => {
+                               if let Ok(payment_key) = chan_utils::derive_public_key(&self.secp_ctx, &their_revocation_point, &PublicKey::from_secret_key(&self.secp_ctx, &payment_base_key)) {
+                                       let to_remote_script =  Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
+                                               .push_slice(&Hash160::hash(&payment_key.serialize())[..])
+                                               .into_script();
+                                       if let Ok(to_remote_key) = chan_utils::derive_private_key(&self.secp_ctx, &their_revocation_point, &payment_base_key) {
+                                               self.to_remote_rescue = Some((to_remote_script, to_remote_key));
+                                       }
+                               }
+                       },
+                       Storage::Watchtower { .. } => {}
+               }
+       }
+
        /// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The
        /// monitor watches for timeouts and may broadcast it if we approach such a timeout. Thus, it
        /// is important that any clones of this channel monitor (including remote clones) by kept
@@ -852,6 +874,7 @@ impl ChannelMonitor {
                                self.current_local_signed_commitment_tx = Some(local_tx);
                        }
                        self.payment_preimages = other.payment_preimages;
+                       self.to_remote_rescue = other.to_remote_rescue;
                }
 
                self.current_remote_commitment_number = cmp::min(self.current_remote_commitment_number, other.current_remote_commitment_number);
@@ -1105,6 +1128,13 @@ impl ChannelMonitor {
 
                self.last_block_hash.write(writer)?;
                self.destination_script.write(writer)?;
+               if let Some((ref to_remote_script, ref local_key)) = self.to_remote_rescue {
+                       writer.write_all(&[1; 1])?;
+                       to_remote_script.write(writer)?;
+                       local_key.write(writer)?;
+               } else {
+                       writer.write_all(&[0; 1])?;
+               }
 
                writer.write_all(&byte_utils::be64_to_array(self.our_claim_txn_waiting_first_conf.len() as u64))?;
                for (ref outpoint, claim_tx_data) in self.our_claim_txn_waiting_first_conf.iter() {
@@ -1733,6 +1763,16 @@ impl ChannelMonitor {
                                        txn_to_broadcast.push(spend_tx);
                                }
                        }
+               } else if let Some((ref to_remote_rescue, ref local_key)) = self.to_remote_rescue {
+                       for (idx, outp) in tx.output.iter().enumerate() {
+                               if to_remote_rescue == &outp.script_pubkey {
+                                       spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WPKH {
+                                               outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 },
+                                               key: local_key.clone(),
+                                               output: outp.clone(),
+                                       });
+                               }
+                       }
                }
 
                (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs)
@@ -2048,9 +2088,16 @@ impl ChannelMonitor {
                None
        }
 
-       /// Used by ChannelManager deserialization to broadcast the latest local state if it's copy of
-       /// the Channel was out-of-date.
-       pub(super) fn get_latest_local_commitment_txn(&self) -> Vec<Transaction> {
+       /// Used by ChannelManager deserialization to broadcast the latest local state if its copy of
+       /// the Channel was out-of-date. You may use it to get a broadcastable local toxic tx in case of
+       /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our remote side knows
+       /// a higher revocation secret than the local commitment number we are aware of. Broadcasting these
+       /// transactions are UNSAFE, as they allow remote side to punish you. Nevertheless you may want to
+       /// broadcast them if remote don't close channel with his higher commitment transaction after a
+       /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact
+       /// out-of-band the other node operator to coordinate with him if option is available to you.
+       /// In any-case, choice is up to the user.
+       pub fn get_latest_local_commitment_txn(&self) -> Vec<Transaction> {
                if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
                        let mut res = vec![local_tx.tx.clone()];
                        match self.key_storage {
@@ -2088,19 +2135,21 @@ impl ChannelMonitor {
                                        }
                                };
                                if funding_txo.is_none() || (prevout.txid == funding_txo.as_ref().unwrap().0.txid && prevout.vout == funding_txo.as_ref().unwrap().0.index as u32) {
-                                       let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height, fee_estimator);
-                                       txn = remote_txn;
-                                       spendable_outputs.append(&mut spendable_output);
-                                       if !new_outputs.1.is_empty() {
-                                               watch_outputs.push(new_outputs);
-                                       }
-                                       if txn.is_empty() {
-                                               let (local_txn, mut spendable_output, new_outputs) = self.check_spend_local_transaction(tx, height);
+                                       if (tx.input[0].sequence >> 8*3) as u8 == 0x80 && (tx.lock_time >> 8*3) as u8 == 0x20 {
+                                               let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height, fee_estimator);
+                                               txn = remote_txn;
                                                spendable_outputs.append(&mut spendable_output);
-                                               txn = local_txn;
                                                if !new_outputs.1.is_empty() {
                                                        watch_outputs.push(new_outputs);
                                                }
+                                               if txn.is_empty() {
+                                                       let (local_txn, mut spendable_output, new_outputs) = self.check_spend_local_transaction(tx, height);
+                                                       spendable_outputs.append(&mut spendable_output);
+                                                       txn = local_txn;
+                                                       if !new_outputs.1.is_empty() {
+                                                               watch_outputs.push(new_outputs);
+                                                       }
+                                               }
                                        }
                                        if !funding_txo.is_none() && txn.is_empty() {
                                                if let Some(spendable_output) = self.check_spend_closing_transaction(tx) {
@@ -2627,6 +2676,15 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
 
                let last_block_hash: Sha256dHash = Readable::read(reader)?;
                let destination_script = Readable::read(reader)?;
+               let to_remote_rescue = match <u8 as Readable<R>>::read(reader)? {
+                       0 => None,
+                       1 => {
+                               let to_remote_script = Readable::read(reader)?;
+                               let local_key = Readable::read(reader)?;
+                               Some((to_remote_script, local_key))
+                       }
+                       _ => return Err(DecodeError::InvalidValue),
+               };
 
                let our_claim_txn_waiting_first_conf_len: u64 = Readable::read(reader)?;
                let mut our_claim_txn_waiting_first_conf = HashMap::with_capacity(cmp::min(our_claim_txn_waiting_first_conf_len as usize, MAX_ALLOC_SIZE / 128));
@@ -2736,6 +2794,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
                        payment_preimages,
 
                        destination_script,
+                       to_remote_rescue,
 
                        our_claim_txn_waiting_first_conf,