Add OnchainTxHandler::get_fully_signed_htlc
[rust-lightning] / lightning / src / ln / channelmonitor.rs
index 2fa416edb2dd79f26c8c0f5433b31e60c135bc2b..f4f03abc3e20835258302766882d09e6b539f4eb 100644 (file)
@@ -443,6 +443,9 @@ pub(crate) enum InputMaterial {
                sigs: (Signature, Signature),
                preimage: Option<PaymentPreimage>,
                amount: u64,
+       },
+       Funding {
+               channel_value: u64,
        }
 }
 
@@ -472,6 +475,10 @@ impl Writeable for InputMaterial  {
                                sigs.1.write(writer)?;
                                preimage.write(writer)?;
                                writer.write_all(&byte_utils::be64_to_array(*amount))?;
+                       },
+                       &InputMaterial::Funding { ref channel_value } => {
+                               writer.write_all(&[3; 1])?;
+                               channel_value.write(writer)?;
                        }
                }
                Ok(())
@@ -521,6 +528,12 @@ impl Readable for InputMaterial {
                                        preimage,
                                        amount
                                }
+                       },
+                       3 => {
+                               let channel_value = Readable::read(reader)?;
+                               InputMaterial::Funding {
+                                       channel_value
+                               }
                        }
                        _ => return Err(DecodeError::InvalidValue),
                };
@@ -767,6 +780,9 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
        // Used just for ChannelManager to make sure it has the latest channel data during
        // deserialization
        current_remote_commitment_number: u64,
+       // Used just for ChannelManager to make sure it has the latest channel data during
+       // deserialization
+       current_local_commitment_number: u64,
 
        payment_preimages: HashMap<PaymentHash, PaymentPreimage>,
 
@@ -823,6 +839,7 @@ impl<ChanSigner: ChannelKeys> PartialEq for ChannelMonitor<ChanSigner> {
                        self.remote_hash_commitment_number != other.remote_hash_commitment_number ||
                        self.prev_local_signed_commitment_tx != other.prev_local_signed_commitment_tx ||
                        self.current_remote_commitment_number != other.current_remote_commitment_number ||
+                       self.current_local_commitment_number != other.current_local_commitment_number ||
                        self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx ||
                        self.payment_preimages != other.payment_preimages ||
                        self.pending_htlcs_updated != other.pending_htlcs_updated ||
@@ -995,6 +1012,12 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
                        writer.write_all(&byte_utils::be48_to_array(0))?;
                }
 
+               if for_local_storage {
+                       writer.write_all(&byte_utils::be48_to_array(self.current_local_commitment_number))?;
+               } else {
+                       writer.write_all(&byte_utils::be48_to_array(0))?;
+               }
+
                writer.write_all(&byte_utils::be64_to_array(self.payment_preimages.len() as u64))?;
                for payment_preimage in self.payment_preimages.values() {
                        writer.write_all(&payment_preimage.0[..])?;
@@ -1113,6 +1136,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        prev_local_signed_commitment_tx: None,
                        current_local_signed_commitment_tx: None,
                        current_remote_commitment_number: 1 << 48,
+                       current_local_commitment_number: 0xffff_ffff_ffff,
 
                        payment_preimages: HashMap::new(),
                        pending_htlcs_updated: Vec::new(),
@@ -1121,7 +1145,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        onchain_events_waiting_threshold_conf: HashMap::new(),
                        outputs_to_watch: HashMap::new(),
 
-                       onchain_tx_handler: OnchainTxHandler::new(destination_script.clone(), keys, funding_redeemscript, logger.clone()),
+                       onchain_tx_handler: OnchainTxHandler::new(destination_script.clone(), keys, funding_redeemscript, their_to_self_delay, logger.clone()),
 
                        last_block_hash: Default::default(),
                        secp_ctx: Secp256k1::new(),
@@ -1246,9 +1270,10 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                // reject update as we do, you MAY have the latest local valid commitment tx onchain
                // for which you want to spend outputs. We're NOT robust again this scenario right
                // now but we should consider it later.
-               if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone()) {
+               if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone(), local_keys.clone(), feerate_per_kw, htlc_outputs.clone()) {
                        return Err(MonitorUpdateError("Local commitment signed has already been signed, no further update of LOCAL commitment transaction is allowed"));
                }
+               self.current_local_commitment_number = 0xffff_ffff_ffff - ((((commitment_tx.without_valid_witness().input[0].sequence as u64 & 0xffffff) << 3*8) | (commitment_tx.without_valid_witness().lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor);
                self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
                self.current_local_signed_commitment_tx = Some(LocalSignedTx {
                        txid: commitment_tx.txid(),
@@ -1259,7 +1284,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        delayed_payment_key: local_keys.a_delayed_payment_key,
                        per_commitment_point: local_keys.per_commitment_point,
                        feerate_per_kw,
-                       htlc_outputs,
+                       htlc_outputs: htlc_outputs,
                });
                Ok(())
        }
@@ -1402,9 +1427,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
        }
 
        pub(super) fn get_cur_local_commitment_number(&self) -> u64 {
-               if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
-                       0xffff_ffff_ffff - ((((local_tx.tx.without_valid_witness().input[0].sequence as u64 & 0xffffff) << 3*8) | (local_tx.tx.without_valid_witness().lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor)
-               } else { 0xffff_ffff_ffff }
+               self.current_local_commitment_number
        }
 
        /// Attempts to claim a remote commitment transaction's outputs using the revocation key and
@@ -1664,7 +1687,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                (claimable_outpoints, Some((htlc_txid, tx.output.clone())))
        }
 
-       fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> (Vec<Transaction>, Vec<TxOut>, Option<(Script, SecretKey, Script)>) {
+       fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec<Transaction>, Vec<TxOut>, Option<(Script, SecretKey, Script)>) {
                let mut res = Vec::with_capacity(local_tx.htlc_outputs.len());
                let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len());
 
@@ -1679,35 +1702,21 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                        if htlc.offered {
                                                log_trace!(self, "Broadcasting HTLC-Timeout transaction against local commitment transactions");
                                                let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
-                                               let (our_sig, htlc_script) = match
-                                                               chan_utils::sign_htlc_transaction(&mut htlc_timeout_tx, their_sig, &None, htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, &self.onchain_detection.keys.htlc_base_key(), &self.secp_ctx) {
-                                                       Ok(res) => res,
-                                                       Err(_) => continue,
-                                               };
+                                               self.onchain_detection.keys.sign_htlc_transaction(&mut htlc_timeout_tx, their_sig, &None, htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, &self.secp_ctx);
 
-                                               let mut per_input_material = HashMap::with_capacity(1);
-                                               per_input_material.insert(htlc_timeout_tx.input[0].previous_output, InputMaterial::LocalHTLC { witness_script: htlc_script, sigs: (*their_sig, our_sig), preimage: None, amount: htlc.amount_msat / 1000});
-                                               //TODO: with option_simplified_commitment track outpoint too
                                                log_trace!(self, "Outpoint {}:{} is being being claimed", htlc_timeout_tx.input[0].previous_output.vout, htlc_timeout_tx.input[0].previous_output.txid);
                                                res.push(htlc_timeout_tx);
                                        } else {
                                                if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
                                                        log_trace!(self, "Broadcasting HTLC-Success transaction against local commitment transactions");
                                                        let mut htlc_success_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key);
-                                                       let (our_sig, htlc_script) = match
-                                                                       chan_utils::sign_htlc_transaction(&mut htlc_success_tx, their_sig, &Some(*payment_preimage), htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, &self.onchain_detection.keys.htlc_base_key(), &self.secp_ctx) {
-                                                               Ok(res) => res,
-                                                               Err(_) => continue,
-                                                       };
-
-                                                       let mut per_input_material = HashMap::with_capacity(1);
-                                                       per_input_material.insert(htlc_success_tx.input[0].previous_output, InputMaterial::LocalHTLC { witness_script: htlc_script, sigs: (*their_sig, our_sig), preimage: Some(*payment_preimage), amount: htlc.amount_msat / 1000});
-                                                       //TODO: with option_simplified_commitment track outpoint too
+                                                       self.onchain_detection.keys.sign_htlc_transaction(&mut htlc_success_tx, their_sig, &Some(*payment_preimage), htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key, &local_tx.per_commitment_point, &self.secp_ctx);
+
                                                        log_trace!(self, "Outpoint {}:{} is being being claimed", htlc_success_tx.input[0].previous_output.vout, htlc_success_tx.input[0].previous_output.txid);
                                                        res.push(htlc_success_tx);
                                                }
                                        }
-                                       watch_outputs.push(local_tx.tx.without_valid_witness().output[transaction_output_index as usize].clone());
+                                       watch_outputs.push(commitment_tx.output[transaction_output_index as usize].clone());
                                } else { panic!("Should have sigs for non-dust local tx outputs!") }
                        }
                }
@@ -1761,7 +1770,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        if local_tx.txid == commitment_txid {
                                is_local_tx = true;
                                log_trace!(self, "Got latest local commitment tx broadcast, searching for available HTLCs to claim");
-                               let mut res = self.broadcast_by_local_state(local_tx);
+                               let mut res = self.broadcast_by_local_state(tx, local_tx);
                                append_onchain_update!(res);
                        }
                }
@@ -1769,8 +1778,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        if local_tx.txid == commitment_txid {
                                is_local_tx = true;
                                log_trace!(self, "Got previous local commitment tx broadcast, searching for available HTLCs to claim");
-                               assert!(local_tx.tx.has_local_sig());
-                               let mut res = self.broadcast_by_local_state(local_tx);
+                               let mut res = self.broadcast_by_local_state(tx, local_tx);
                                append_onchain_update!(res);
                        }
                }
@@ -1809,22 +1817,49 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
        /// 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(&mut self) -> Vec<Transaction> {
-               // TODO: We should likely move all of the logic in here into OnChainTxHandler and unify it
-               // to ensure add_local_sig is only ever called once no matter what. This likely includes
-               // tracking state and panic!()ing if we get an update after force-closure/local-tx signing.
                log_trace!(self, "Getting signed latest local commitment transaction!");
-               if let &mut Some(ref mut local_tx) = &mut self.current_local_signed_commitment_tx {
-                       self.onchain_detection.keys.sign_local_commitment(&mut local_tx.tx, self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &self.secp_ctx);
+               if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(self.channel_value_satoshis.unwrap()) {
+                       let txid = commitment_tx.txid();
+                       let mut res = vec![commitment_tx];
+                       if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
+                               for htlc in local_tx.htlc_outputs.iter() {
+                                       if let Some(htlc_index) = htlc.0.transaction_output_index {
+                                               let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
+                                               if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
+                                                       res.push(htlc_tx);
+                                               }
+                                       }
+                               }
+                               // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
+                               // The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation.
+                       }
+                       return res
                }
-               if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
-                       let mut res = vec![local_tx.tx.with_valid_witness().clone()];
-                       res.append(&mut self.broadcast_by_local_state(local_tx).0);
-                       // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
-                       // The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation.
-                       res
-               } else {
-                       Vec::new()
+               Vec::new()
+       }
+
+       /// Unsafe test-only version of get_latest_local_commitment_txn used by our test framework
+       /// to bypass LocalCommitmentTransaction state update lockdown after signature and generate
+       /// revoked commitment transaction.
+       #[cfg(test)]
+       pub fn unsafe_get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> {
+               log_trace!(self, "Getting signed copy of latest local commitment transaction!");
+               if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(self.channel_value_satoshis.unwrap()) {
+                       let txid = commitment_tx.txid();
+                       let mut res = vec![commitment_tx];
+                       if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
+                               for htlc in local_tx.htlc_outputs.iter() {
+                                       if let Some(htlc_index) = htlc.0.transaction_output_index {
+                                               let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
+                                               if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
+                                                       res.push(htlc_tx);
+                                               }
+                                       }
+                               }
+                       }
+                       return res
                }
+               Vec::new()
        }
 
        /// Called by SimpleManyChannelMonitor::block_connected, which implements
@@ -1894,22 +1929,20 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                let should_broadcast = if let Some(_) = self.current_local_signed_commitment_tx {
                        self.would_broadcast_at_height(height)
                } else { false };
-               if let Some(ref mut cur_local_tx) = self.current_local_signed_commitment_tx {
-                       if should_broadcast {
-                               self.onchain_detection.keys.sign_local_commitment(&mut cur_local_tx.tx, self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &mut self.secp_ctx);
-                       }
+               if should_broadcast {
+                       claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.onchain_detection.funding_info.as_ref().unwrap().0.txid.clone(), vout: self.onchain_detection.funding_info.as_ref().unwrap().0.index as u32 }, witness_data: InputMaterial::Funding { channel_value: self.channel_value_satoshis.unwrap() }});
                }
                if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
                        if should_broadcast {
-                               log_trace!(self, "Broadcast onchain {}", log_tx!(cur_local_tx.tx.with_valid_witness()));
-                               broadcaster.broadcast_transaction(&cur_local_tx.tx.with_valid_witness());
-                               let (txs, new_outputs, _) = self.broadcast_by_local_state(&cur_local_tx);
-                               if !new_outputs.is_empty() {
-                                       watch_outputs.push((cur_local_tx.txid.clone(), new_outputs));
-                               }
-                               for tx in txs {
-                                       log_trace!(self, "Broadcast onchain {}", log_tx!(tx));
-                                       broadcaster.broadcast_transaction(&tx);
+                               if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(self.channel_value_satoshis.unwrap()) {
+                                       let (txs, new_outputs, _) = self.broadcast_by_local_state(&commitment_tx, cur_local_tx);
+                                       if !new_outputs.is_empty() {
+                                               watch_outputs.push((cur_local_tx.txid.clone(), new_outputs));
+                                       }
+                                       for tx in txs {
+                                               log_trace!(self, "Broadcast onchain {}", log_tx!(tx));
+                                               broadcaster.broadcast_transaction(&tx);
+                                       }
                                }
                        }
                }
@@ -2382,7 +2415,8 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dH
 
                                        LocalSignedTx {
                                                txid: tx.txid(),
-                                               tx, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw,
+                                               tx,
+                                               revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw,
                                                htlc_outputs: htlcs
                                        }
                                }
@@ -2406,6 +2440,7 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dH
                };
 
                let current_remote_commitment_number = <U48 as Readable>::read(reader)?.0;
+               let current_local_commitment_number = <U48 as Readable>::read(reader)?.0;
 
                let payment_preimages_len: u64 = Readable::read(reader)?;
                let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32));
@@ -2503,6 +2538,7 @@ impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dH
                        prev_local_signed_commitment_tx,
                        current_local_signed_commitment_tx,
                        current_remote_commitment_number,
+                       current_local_commitment_number,
 
                        payment_preimages,
                        pending_htlcs_updated,