From: Devrandom Date: Thu, 14 Jan 2021 21:45:31 +0000 (-0800) Subject: Simplify handling of OnChainTx.holder_commitment X-Git-Tag: v0.0.13~43^2 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=0b20cf62e78dc6cfbe34772af0f9f7481ec68ef5;p=rust-lightning Simplify handling of OnChainTx.holder_commitment It is no longer optional since it is available at construction time. --- diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index b87e73d98..b46a2df13 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -969,7 +969,6 @@ impl ChannelMonitor { let key_derivation_params = keys.key_derivation_params(); let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint; - let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone()); let secp_ctx = Secp256k1::new(); @@ -991,7 +990,9 @@ impl ChannelMonitor { }; (holder_commitment_tx, trusted_tx.commitment_number()) }; - onchain_tx_handler.provide_latest_holder_tx(initial_holder_commitment_tx); + + let onchain_tx_handler = + OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone(), initial_holder_commitment_tx); let mut outputs_to_watch = HashMap::new(); outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]); @@ -1725,28 +1726,26 @@ impl ChannelMonitor { pub fn get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { log_trace!(logger, "Getting signed latest holder commitment transaction!"); self.holder_tx_signed = true; - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) { - let txid = commitment_tx.txid(); - let mut res = vec![commitment_tx]; - for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { - if let Some(vout) = htlc.0.transaction_output_index { - let preimage = if !htlc.0.offered { - if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { - // We can't build an HTLC-Success transaction without the preimage - continue; - } - } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx( - &::bitcoin::OutPoint { txid, vout }, &preimage) { - res.push(htlc_tx); + let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); + let txid = commitment_tx.txid(); + let mut res = vec![commitment_tx]; + for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { + if let Some(vout) = htlc.0.transaction_output_index { + let preimage = if !htlc.0.offered { + if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { + // We can't build an HTLC-Success transaction without the preimage + continue; } + } else { None }; + if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx( + &::bitcoin::OutPoint { txid, vout }, &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_holder_transaction if we get a confirmation. - return res } - Vec::new() + // 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_holder_transaction if we get a confirmation. + return res; } /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework @@ -1755,26 +1754,24 @@ impl ChannelMonitor { #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] pub fn unsafe_get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { log_trace!(logger, "Getting signed copy of latest holder commitment transaction!"); - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript) { - let txid = commitment_tx.txid(); - let mut res = vec![commitment_tx]; - for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { - if let Some(vout) = htlc.0.transaction_output_index { - let preimage = if !htlc.0.offered { - if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { - // We can't build an HTLC-Success transaction without the preimage - continue; - } - } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx( - &::bitcoin::OutPoint { txid, vout }, &preimage) { - res.push(htlc_tx); + let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript); + let txid = commitment_tx.txid(); + let mut res = vec![commitment_tx]; + for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { + if let Some(vout) = htlc.0.transaction_output_index { + let preimage = if !htlc.0.offered { + if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { + // We can't build an HTLC-Success transaction without the preimage + continue; } + } else { None }; + if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx( + &::bitcoin::OutPoint { txid, vout }, &preimage) { + res.push(htlc_tx); } } - return res } - Vec::new() + return res } /// Processes transactions in a newly connected block, which may result in any of the following: @@ -1853,15 +1850,14 @@ impl ChannelMonitor { } if should_broadcast { self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0)); - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) { - self.holder_tx_signed = true; - let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx); - let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx); - if !new_outputs.is_empty() { - watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs)); - } - claimable_outpoints.append(&mut new_outpoints); - } + let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); + self.holder_tx_signed = true; + let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx); + let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx); + if !new_outputs.is_empty() { + watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs)); + } + claimable_outpoints.append(&mut new_outpoints); } if let Some(events) = self.onchain_events_waiting_threshold_conf.remove(&height) { for ev in events { diff --git a/lightning/src/ln/onchaintx.rs b/lightning/src/ln/onchaintx.rs index 9e77ac974..02776fdef 100644 --- a/lightning/src/ln/onchaintx.rs +++ b/lightning/src/ln/onchaintx.rs @@ -35,6 +35,7 @@ use util::byte_utils; use std::collections::{HashMap, hash_map}; use std::cmp; use std::ops::Deref; +use std::mem::replace; const MAX_ALLOC_SIZE: usize = 64*1024; @@ -241,7 +242,7 @@ impl Writeable for Option>> { /// do RBF bumping if possible. pub struct OnchainTxHandler { destination_script: Script, - holder_commitment: Option, + holder_commitment: HolderCommitmentTransaction, // holder_htlc_sigs and prev_holder_htlc_sigs are in the order as they appear in the commitment // transaction outputs (hence the Option<>s inside the Vec). The first usize is the index in // the set of HTLCs in the HolderCommitmentTransaction. @@ -423,13 +424,13 @@ impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler OnchainTxHandler { - pub(crate) fn new(destination_script: Script, keys: ChanSigner, channel_parameters: ChannelTransactionParameters) -> Self { + pub(crate) fn new(destination_script: Script, keys: ChanSigner, channel_parameters: ChannelTransactionParameters, holder_commitment: HolderCommitmentTransaction) -> Self { let key_storage = keys; OnchainTxHandler { destination_script, - holder_commitment: None, + holder_commitment, holder_htlc_sigs: None, prev_holder_commitment: None, prev_holder_htlc_sigs: None, @@ -663,10 +664,10 @@ impl OnchainTxHandler { return None; }, &InputMaterial::Funding { ref funding_redeemscript } => { - let signed_tx = self.get_fully_signed_holder_tx(funding_redeemscript).unwrap(); + let signed_tx = self.get_fully_signed_holder_tx(funding_redeemscript); // Timer set to $NEVER given we can't bump tx without anchor outputs log_trace!(logger, "Going to broadcast Holder Transaction {} claiming funding output {} from {}...", signed_tx.txid(), outp.vout, outp.txid); - return Some((None, self.holder_commitment.as_ref().unwrap().feerate_per_kw(), signed_tx)); + return Some((None, self.holder_commitment.feerate_per_kw(), signed_tx)); } _ => unreachable!() } @@ -904,9 +905,8 @@ impl OnchainTxHandler { } pub(crate) fn provide_latest_holder_tx(&mut self, tx: HolderCommitmentTransaction) { - self.prev_holder_commitment = self.holder_commitment.take(); + self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx)); self.holder_htlc_sigs = None; - self.holder_commitment = Some(tx); } // Normally holder HTLCs are signed at the same time as the holder commitment tx. However, @@ -914,15 +914,13 @@ impl OnchainTxHandler { // ChannelMonitor replica, so we handle that case here. fn sign_latest_holder_htlcs(&mut self) { if self.holder_htlc_sigs.is_none() { - if let Some(ref holder_commitment) = self.holder_commitment { - let (_sig, sigs) = self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx).expect("sign holder commitment"); - self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs)); - } + let (_sig, sigs) = self.key_storage.sign_holder_commitment_and_htlcs(&self.holder_commitment, &self.secp_ctx).expect("sign holder commitment"); + self.holder_htlc_sigs = Some(Self::extract_holder_sigs(&self.holder_commitment, sigs)); } } // Normally only the latest commitment tx and HTLCs need to be signed. However, in some - // configurations we may have updated our holder commtiment but a replica of the ChannelMonitor + // configurations we may have updated our holder commitment but a replica of the ChannelMonitor // broadcast the previous one before we sync with it. We handle that case here. fn sign_prev_holder_htlcs(&mut self) { if self.prev_holder_htlc_sigs.is_none() { @@ -947,43 +945,34 @@ impl OnchainTxHandler { // have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after Channel::get_outbound_funding_created, // before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing // to monitor before. - pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Option { - if let Some(ref mut holder_commitment) = self.holder_commitment { - let (sig, htlc_sigs) = self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx).expect("signing holder commitment"); - self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs)); - Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)) - } else { - None - } + pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction { + let (sig, htlc_sigs) = self.key_storage.sign_holder_commitment_and_htlcs(&self.holder_commitment, &self.secp_ctx).expect("signing holder commitment"); + self.holder_htlc_sigs = Some(Self::extract_holder_sigs(&self.holder_commitment, htlc_sigs)); + self.holder_commitment.add_holder_sig(funding_redeemscript, sig) } #[cfg(any(test, feature="unsafe_revoked_tx_signing"))] - pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Option { - if let Some(ref mut holder_commitment) = self.holder_commitment { - let (sig, htlc_sigs) = self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx).expect("sign holder commitment"); - self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs)); - Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)) - } else { - None - } + pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction { + let (sig, htlc_sigs) = self.key_storage.sign_holder_commitment_and_htlcs(&self.holder_commitment, &self.secp_ctx).expect("sign holder commitment"); + self.holder_htlc_sigs = Some(Self::extract_holder_sigs(&self.holder_commitment, htlc_sigs)); + self.holder_commitment.add_holder_sig(funding_redeemscript, sig) } pub(crate) fn get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option) -> Option { let mut htlc_tx = None; - if self.holder_commitment.is_some() { - let commitment_txid = self.holder_commitment.as_ref().unwrap().trust().txid(); - if commitment_txid == outp.txid { - self.sign_latest_holder_htlcs(); - if let &Some(ref htlc_sigs) = &self.holder_htlc_sigs { - let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap(); - let holder_commitment = self.holder_commitment.as_ref().unwrap(); - let trusted_tx = holder_commitment.trust(); - let counterparty_htlc_sig = holder_commitment.counterparty_htlc_sigs[*htlc_idx]; - htlc_tx = Some(trusted_tx - .get_signed_htlc_tx(&self.channel_transaction_parameters.as_holder_broadcastable(), *htlc_idx, &counterparty_htlc_sig, htlc_sig, preimage)); - } + let commitment_txid = self.holder_commitment.trust().txid(); + // Check if the HTLC spends from the current holder commitment + if commitment_txid == outp.txid { + self.sign_latest_holder_htlcs(); + if let &Some(ref htlc_sigs) = &self.holder_htlc_sigs { + let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap(); + let trusted_tx = self.holder_commitment.trust(); + let counterparty_htlc_sig = self.holder_commitment.counterparty_htlc_sigs[*htlc_idx]; + htlc_tx = Some(trusted_tx + .get_signed_htlc_tx(&self.channel_transaction_parameters.as_holder_broadcastable(), *htlc_idx, &counterparty_htlc_sig, htlc_sig, preimage)); } } + // If the HTLC doesn't spend the current holder commitment, check if it spends the previous one if htlc_tx.is_none() && self.prev_holder_commitment.is_some() { let commitment_txid = self.prev_holder_commitment.as_ref().unwrap().trust().txid(); if commitment_txid == outp.txid {