Fold sign_holder_commitment_htlc_transactions into sign_holder_commitment
[rust-lightning] / lightning / src / ln / onchaintx.rs
index 513e4a136dc742dc9d5f2ad8268271658d7ff511..80ad434ce403abdf1bc61106507dffe6e2fd6ea2 100644 (file)
@@ -27,9 +27,9 @@ use ln::chan_utils;
 use ln::chan_utils::{TxCreationKeys, ChannelTransactionParameters, HolderCommitmentTransaction};
 use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
 use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
-use chain::keysinterface::ChannelKeys;
+use chain::keysinterface::{ChannelKeys, KeysInterface};
 use util::logger::Logger;
-use util::ser::{Readable, Writer, Writeable};
+use util::ser::{Readable, ReadableArgs, Writer, Writeable, VecWriter};
 use util::byte_utils;
 
 use std::collections::{HashMap, hash_map};
@@ -294,9 +294,15 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                self.prev_holder_commitment.write(writer)?;
                self.prev_holder_htlc_sigs.write(writer)?;
 
-               self.key_storage.write(writer)?;
                self.channel_transaction_parameters.write(writer)?;
 
+               let mut key_data = VecWriter(Vec::new());
+               self.key_storage.write(&mut key_data)?;
+               assert!(key_data.0.len() < std::usize::MAX);
+               assert!(key_data.0.len() < std::u32::MAX as usize);
+               (key_data.0.len() as u32).write(writer)?;
+               writer.write_all(&key_data.0[..])?;
+
                writer.write_all(&byte_utils::be64_to_array(self.pending_claim_requests.len() as u64))?;
                for (ref ancestor_claim_txid, claim_tx_data) in self.pending_claim_requests.iter() {
                        ancestor_claim_txid.write(writer)?;
@@ -333,8 +339,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
        }
 }
 
-impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigner> {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+impl<'a, K: KeysInterface> ReadableArgs<&'a K> for OnchainTxHandler<K::ChanKeySigner> {
+       fn read<R: ::std::io::Read>(reader: &mut R, keys_manager: &'a K) -> Result<Self, DecodeError> {
                let destination_script = Readable::read(reader)?;
 
                let holder_commitment = Readable::read(reader)?;
@@ -342,9 +348,19 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
                let prev_holder_commitment = Readable::read(reader)?;
                let prev_holder_htlc_sigs = Readable::read(reader)?;
 
-               let key_storage = Readable::read(reader)?;
                let channel_parameters = Readable::read(reader)?;
 
+               let keys_len: u32 = Readable::read(reader)?;
+               let mut keys_data = Vec::with_capacity(cmp::min(keys_len as usize, MAX_ALLOC_SIZE));
+               while keys_data.len() != keys_len as usize {
+                       // Read 1KB at a time to avoid accidentally allocating 4GB on corrupted channel keys
+                       let mut data = [0; 1024];
+                       let read_slice = &mut data[0..cmp::min(1024, keys_len as usize - keys_data.len())];
+                       reader.read_exact(read_slice)?;
+                       keys_data.extend_from_slice(read_slice);
+               }
+               let key_storage = keys_manager.read_chan_signer(&keys_data)?;
+
                let pending_claim_requests_len: u64 = Readable::read(reader)?;
                let mut pending_claim_requests = HashMap::with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
                for _ in 0..pending_claim_requests_len {
@@ -474,6 +490,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
 
        /// Lightning security model (i.e being able to redeem/timeout HTLC or penalize coutnerparty onchain) lays on the assumption of claim transactions getting confirmed before timelock expiration
        /// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent.
+       /// Panics if there are signing errors, because signing operations in reaction to on-chain events
+       /// are not expected to fail, and if they do, we may lose funds.
        fn generate_claim_tx<F: Deref, L: Deref>(&mut self, height: u32, cached_claim_datas: &ClaimTxBumpMaterial, fee_estimator: &F, logger: &L) -> Option<(Option<u32>, u32, Transaction)>
                where F::Target: FeeEstimator,
                                        L::Target: Logger,
@@ -890,20 +908,29 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
 
        pub(crate) fn provide_latest_holder_tx(&mut self, tx: HolderCommitmentTransaction) {
                self.prev_holder_commitment = self.holder_commitment.take();
+               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,
+       // in some configurations, the holder commitment tx has been signed and broadcast by a
+       // ChannelMonitor replica, so we handle that case here.
        fn sign_latest_holder_htlcs(&mut self) {
-               if let Some(ref holder_commitment) = self.holder_commitment {
-                       if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
+               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));
                        }
                }
        }
 
+       // 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
+       // broadcast the previous one before we sync with it.  We handle that case here.
        fn sign_prev_holder_htlcs(&mut self) {
-               if let Some(ref holder_commitment) = self.prev_holder_commitment {
-                       if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
+               if self.prev_holder_htlc_sigs.is_none() {
+                       if let Some(ref holder_commitment) = self.prev_holder_commitment {
+                               let (_sig, sigs) = self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx).expect("sign previous holder commitment");
                                self.prev_holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs));
                        }
                }
@@ -925,8 +952,9 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
        // to monitor before.
        pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
                if let Some(ref mut holder_commitment) = self.holder_commitment {
-                       match self.key_storage.sign_holder_commitment(&holder_commitment, &self.secp_ctx) {
-                               Ok(sig) => {
+                       match self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx) {
+                               Ok((sig, htlc_sigs)) => {
+                                       self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs));
                                        Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
                                },
                                Err(_) => return None,
@@ -939,8 +967,9 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
        #[cfg(any(test, feature="unsafe_revoked_tx_signing"))]
        pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
                if let Some(ref mut holder_commitment) = self.holder_commitment {
-                       match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
-                               Ok(sig) => {
+                       match self.key_storage.sign_holder_commitment_and_htlcs(holder_commitment, &self.secp_ctx) {
+                               Ok((sig, htlc_sigs)) => {
+                                       self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs));
                                        Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
                                },
                                Err(_) => return None,
@@ -966,7 +995,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                                }
                        }
                }
-               if self.prev_holder_commitment.is_some() {
+               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 {
                                self.sign_prev_holder_htlcs();