Rename ChannelKeys -> Sign and generic it consistently
[rust-lightning] / lightning / src / ln / channel.rs
index 10b6b28b7737b7851b0667f1c6508cbbf23af07b..2617bec03f03a113f45850ce7195b0bf6fd97a2a 100644 (file)
@@ -31,9 +31,9 @@ use ln::chan_utils;
 use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
 use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER};
 use chain::transaction::{OutPoint, TransactionData};
-use chain::keysinterface::{ChannelKeys, KeysInterface};
+use chain::keysinterface::{Sign, KeysInterface};
 use util::transaction_utils;
-use util::ser::{Readable, Writeable, Writer};
+use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter};
 use util::logger::Logger;
 use util::errors::APIError;
 use util::config::{UserConfig,ChannelConfig};
@@ -42,6 +42,8 @@ use std;
 use std::default::Default;
 use std::{cmp,mem,fmt};
 use std::ops::Deref;
+#[cfg(any(test, feature = "fuzztarget"))]
+use std::sync::Mutex;
 use bitcoin::hashes::hex::ToHex;
 
 #[cfg(test)]
@@ -258,6 +260,27 @@ enum UpdateStatus {
        DisabledStaged,
 }
 
+/// An enum indicating whether the local or remote side offered a given HTLC.
+enum HTLCInitiator {
+       LocalOffered,
+       RemoteOffered,
+}
+
+/// Used when calculating whether we or the remote can afford an additional HTLC.
+struct HTLCCandidate {
+       amount_msat: u64,
+       origin: HTLCInitiator,
+}
+
+impl HTLCCandidate {
+       fn new(amount_msat: u64, origin: HTLCInitiator) -> Self {
+               Self {
+                       amount_msat,
+                       origin,
+               }
+       }
+}
+
 // TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
 // has been completed, and then turn into a Channel to get compiler-time enforcement of things like
 // calling channel_id() before we're set up or things like get_outbound_funding_signed on an
@@ -265,7 +288,7 @@ enum UpdateStatus {
 //
 // Holder designates channel data owned for the benefice of the user client.
 // Counterparty designates channel data owned by the another channel participant entity.
-pub(super) struct Channel<ChanSigner: ChannelKeys> {
+pub(super) struct Channel<Signer: Sign> {
        config: ChannelConfig,
 
        user_id: u64,
@@ -278,9 +301,9 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
        latest_monitor_update_id: u64,
 
        #[cfg(not(test))]
-       holder_keys: ChanSigner,
+       holder_keys: Signer,
        #[cfg(test)]
-       pub(super) holder_keys: ChanSigner,
+       pub(super) holder_keys: Signer,
        shutdown_pubkey: PublicKey,
        destination_script: Script,
 
@@ -386,6 +409,24 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
        commitment_secrets: CounterpartyCommitmentSecrets,
 
        network_sync: UpdateStatus,
+
+       // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
+       // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
+       // be, by comparing the cached values to the fee of the tranaction generated by
+       // `build_commitment_transaction`.
+       #[cfg(any(test, feature = "fuzztarget"))]
+       next_local_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
+       #[cfg(any(test, feature = "fuzztarget"))]
+       next_remote_commitment_tx_fee_info_cached: Mutex<Option<CommitmentTxInfoCached>>,
+}
+
+#[cfg(any(test, feature = "fuzztarget"))]
+struct CommitmentTxInfoCached {
+       fee: u64,
+       total_pending_htlcs: usize,
+       next_holder_htlc_id: u64,
+       next_counterparty_htlc_id: u64,
+       feerate: u32,
 }
 
 pub const OUR_MAX_HTLCS: u16 = 50; //TODO
@@ -437,7 +478,7 @@ macro_rules! secp_check {
        };
 }
 
-impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
+impl<Signer: Sign> Channel<Signer> {
        // Convert constants + channel value to limits:
        fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 {
                channel_value_satoshis * 1000 / 10 //TODO
@@ -457,12 +498,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        }
 
        // Constructors:
-       pub fn new_outbound<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig) -> Result<Channel<ChanSigner>, APIError>
-       where K::Target: KeysInterface<ChanKeySigner = ChanSigner>,
+       pub fn new_outbound<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig) -> Result<Channel<Signer>, APIError>
+       where K::Target: KeysInterface<Signer = Signer>,
              F::Target: FeeEstimator,
        {
                let holder_selected_contest_delay = config.own_channel_config.our_to_self_delay;
-               let chan_keys = keys_provider.get_channel_keys(false, channel_value_satoshis);
+               let chan_keys = keys_provider.get_channel_signer(false, channel_value_satoshis);
                let pubkeys = chan_keys.pubkeys().clone();
 
                if channel_value_satoshis >= MAX_FUNDING_SATOSHIS {
@@ -476,7 +517,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)});
                }
                let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
-               if Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis) < Channel::<ChanSigner>::derive_holder_dust_limit_satoshis(background_feerate) {
+               if Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis) < Channel::<Signer>::derive_holder_dust_limit_satoshis(background_feerate) {
                        return Err(APIError::FeeRateTooHigh{err: format!("Not enough reserve above dust limit can be found at current fee rate({})", background_feerate), feerate: background_feerate});
                }
 
@@ -532,7 +573,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
                        feerate_per_kw: feerate,
                        counterparty_dust_limit_satoshis: 0,
-                       holder_dust_limit_satoshis: Channel::<ChanSigner>::derive_holder_dust_limit_satoshis(background_feerate),
+                       holder_dust_limit_satoshis: Channel::<Signer>::derive_holder_dust_limit_satoshis(background_feerate),
                        counterparty_max_htlc_value_in_flight_msat: 0,
                        counterparty_selected_channel_reserve_satoshis: 0,
                        counterparty_htlc_minimum_msat: 0,
@@ -557,6 +598,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        commitment_secrets: CounterpartyCommitmentSecrets::new(),
 
                        network_sync: UpdateStatus::Fresh,
+
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_local_commitment_tx_fee_info_cached: Mutex::new(None),
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
                })
        }
 
@@ -576,11 +622,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
        /// Creates a new channel from a remote sides' request for one.
        /// Assumes chain_hash has already been checked and corresponds with what we expect!
-       pub fn new_from_req<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig) -> Result<Channel<ChanSigner>, ChannelError>
-               where K::Target: KeysInterface<ChanKeySigner = ChanSigner>,
+       pub fn new_from_req<K: Deref, F: Deref>(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig) -> Result<Channel<Signer>, ChannelError>
+               where K::Target: KeysInterface<Signer = Signer>,
           F::Target: FeeEstimator
        {
-               let chan_keys = keys_provider.get_channel_keys(true, msg.funding_satoshis);
+               let chan_keys = keys_provider.get_channel_signer(true, msg.funding_satoshis);
                let pubkeys = chan_keys.pubkeys().clone();
                let counterparty_pubkeys = ChannelPublicKeys {
                        funding_pubkey: msg.funding_pubkey,
@@ -616,7 +662,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                if msg.htlc_minimum_msat >= full_channel_value_msat {
                        return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
                }
-               Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+               Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
 
                let max_counterparty_selected_contest_delay = u16::min(config.peer_channel_config_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
                if msg.to_self_delay > max_counterparty_selected_contest_delay {
@@ -665,8 +711,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
                let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
 
-               let holder_dust_limit_satoshis = Channel::<ChanSigner>::derive_holder_dust_limit_satoshis(background_feerate);
-               let holder_selected_channel_reserve_satoshis = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
+               let holder_dust_limit_satoshis = Channel::<Signer>::derive_holder_dust_limit_satoshis(background_feerate);
+               let holder_selected_channel_reserve_satoshis = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis);
                if holder_selected_channel_reserve_satoshis < holder_dust_limit_satoshis {
                        return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, holder_dust_limit_satoshis)));
                }
@@ -790,6 +836,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        commitment_secrets: CounterpartyCommitmentSecrets::new(),
 
                        network_sync: UpdateStatus::Fresh,
+
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_local_commitment_tx_fee_info_cached: Mutex::new(None),
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
                };
 
                Ok(chan)
@@ -936,7 +987,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        };
                        debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.counterparty_selected_channel_reserve_satoshis as i64);
                        broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64);
-                       debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64);
+                       debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64);
                        broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
                }
 
@@ -1346,7 +1397,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                if msg.channel_reserve_satoshis < self.holder_dust_limit_satoshis {
                        return Err(ChannelError::Close(format!("Peer never wants payout outputs? channel_reserve_satoshis was ({}). dust_limit is ({})", msg.channel_reserve_satoshis, self.holder_dust_limit_satoshis)));
                }
-               let remote_reserve = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
+               let remote_reserve = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
                if msg.dust_limit_satoshis > remote_reserve {
                        return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, remote_reserve)));
                }
@@ -1469,7 +1520,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                &self.get_counterparty_pubkeys().funding_pubkey
        }
 
-       pub fn funding_created<L: Deref>(&mut self, msg: &msgs::FundingCreated, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor<ChanSigner>), ChannelError> where L::Target: Logger {
+       pub fn funding_created<L: Deref>(&mut self, msg: &msgs::FundingCreated, logger: &L) -> Result<(msgs::FundingSigned, ChannelMonitor<Signer>), ChannelError> where L::Target: Logger {
                if self.is_outbound() {
                        return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned()));
                }
@@ -1540,7 +1591,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
        /// Handles a funding_signed message from the remote end.
        /// If this call is successful, broadcast the funding transaction (and not before!)
-       pub fn funding_signed<L: Deref>(&mut self, msg: &msgs::FundingSigned, logger: &L) -> Result<ChannelMonitor<ChanSigner>, ChannelError> where L::Target: Logger {
+       pub fn funding_signed<L: Deref>(&mut self, msg: &msgs::FundingSigned, logger: &L) -> Result<ChannelMonitor<Signer>, ChannelError> where L::Target: Logger {
                if !self.is_outbound() {
                        return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned()));
                }
@@ -1684,63 +1735,172 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000
        }
 
-       // Get the commitment tx fee for the local (i.e our) next commitment transaction
-       // based on the number of pending HTLCs that are on track to be in our next
-       // commitment tx. `addl_htcs` is an optional parameter allowing the caller
-       // to add a number of additional HTLCs to the calculation. Note that dust
-       // HTLCs are excluded.
-       fn next_local_commit_tx_fee_msat(&self, addl_htlcs: usize) -> u64 {
+       // Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
+       // number of pending HTLCs that are on track to be in our next commitment tx, plus an additional
+       // HTLC if `fee_spike_buffer_htlc` is Some, plus a new HTLC given by `new_htlc_amount`. Dust HTLCs
+       // are excluded.
+       fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
                assert!(self.is_outbound());
 
-               let mut their_acked_htlcs = self.pending_inbound_htlcs.len();
+               let real_dust_limit_success_sat = (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+               let real_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
+
+               let mut addl_htlcs = 0;
+               if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
+               match htlc.origin {
+                       HTLCInitiator::LocalOffered => {
+                               if htlc.amount_msat / 1000 >= real_dust_limit_timeout_sat {
+                                       addl_htlcs += 1;
+                               }
+                       },
+                       HTLCInitiator::RemoteOffered => {
+                               if htlc.amount_msat / 1000 >= real_dust_limit_success_sat {
+                                       addl_htlcs += 1;
+                               }
+                       }
+               }
+
+               let mut included_htlcs = 0;
+               for ref htlc in self.pending_inbound_htlcs.iter() {
+                       if htlc.amount_msat / 1000 < real_dust_limit_success_sat {
+                               continue
+                       }
+                       // We include LocalRemoved HTLCs here because we may still need to broadcast a commitment
+                       // transaction including this HTLC if it times out before they RAA.
+                       included_htlcs += 1;
+               }
+
                for ref htlc in self.pending_outbound_htlcs.iter() {
-                       if htlc.amount_msat / 1000 <= self.holder_dust_limit_satoshis {
+                       if htlc.amount_msat / 1000 < real_dust_limit_timeout_sat {
                                continue
                        }
                        match htlc.state {
-                               OutboundHTLCState::Committed => their_acked_htlcs += 1,
-                               OutboundHTLCState::RemoteRemoved {..} => their_acked_htlcs += 1,
-                               OutboundHTLCState::LocalAnnounced {..} => their_acked_htlcs += 1,
+                               OutboundHTLCState::LocalAnnounced {..} => included_htlcs += 1,
+                               OutboundHTLCState::Committed => included_htlcs += 1,
+                               OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
+                               // We don't include AwaitingRemoteRevokeToRemove HTLCs because our next commitment
+                               // transaction won't be generated until they send us their next RAA, which will mean
+                               // dropping any HTLCs in this state.
                                _ => {},
                        }
                }
 
                for htlc in self.holding_cell_htlc_updates.iter() {
                        match htlc {
-                               &HTLCUpdateAwaitingACK::AddHTLC { .. } => their_acked_htlcs += 1,
-                               _ => {},
+                               &HTLCUpdateAwaitingACK::AddHTLC { amount_msat, .. } => {
+                                       if amount_msat / 1000 < real_dust_limit_timeout_sat {
+                                               continue
+                                       }
+                                       included_htlcs += 1
+                               },
+                               _ => {}, // Don't include claims/fails that are awaiting ack, because once we get the
+                                        // ack we're guaranteed to never include them in commitment txs anymore.
                        }
                }
 
-               self.commit_tx_fee_msat(their_acked_htlcs + addl_htlcs)
+               let num_htlcs = included_htlcs + addl_htlcs;
+               let res = self.commit_tx_fee_msat(num_htlcs);
+               #[cfg(any(test, feature = "fuzztarget"))]
+               {
+                       let mut fee = res;
+                       if fee_spike_buffer_htlc.is_some() {
+                               fee = self.commit_tx_fee_msat(num_htlcs - 1);
+                       }
+                       let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
+                               + self.holding_cell_htlc_updates.len();
+                       let commitment_tx_info = CommitmentTxInfoCached {
+                               fee,
+                               total_pending_htlcs,
+                               next_holder_htlc_id: match htlc.origin {
+                                       HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
+                                       HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
+                               },
+                               next_counterparty_htlc_id: match htlc.origin {
+                                       HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
+                                       HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
+                               },
+                               feerate: self.feerate_per_kw,
+                       };
+                       *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
+               }
+               res
        }
 
-       // Get the commitment tx fee for the remote's next commitment transaction
-       // based on the number of pending HTLCs that are on track to be in their
-       // next commitment tx. `addl_htcs` is an optional parameter allowing the caller
-       // to add a number of additional HTLCs to the calculation. Note that dust HTLCs
-       // are excluded.
-       fn next_remote_commit_tx_fee_msat(&self, addl_htlcs: usize) -> u64 {
+       // Get the commitment tx fee for the remote's next commitment transaction based on the number of
+       // pending HTLCs that are on track to be in their next commitment tx, plus an additional HTLC if
+       // `fee_spike_buffer_htlc` is Some, plus a new HTLC given by `new_htlc_amount`. Dust HTLCs are
+       // excluded.
+       fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 {
                assert!(!self.is_outbound());
 
-               // When calculating the set of HTLCs which will be included in their next
-               // commitment_signed, all inbound HTLCs are included (as all states imply it will be
-               // included) and only committed outbound HTLCs, see below.
-               let mut their_acked_htlcs = self.pending_inbound_htlcs.len();
+               let real_dust_limit_success_sat = (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+               let real_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
+
+               let mut addl_htlcs = 0;
+               if fee_spike_buffer_htlc.is_some() { addl_htlcs += 1; }
+               match htlc.origin {
+                       HTLCInitiator::LocalOffered => {
+                               if htlc.amount_msat / 1000 >= real_dust_limit_success_sat {
+                                       addl_htlcs += 1;
+                               }
+                       },
+                       HTLCInitiator::RemoteOffered => {
+                               if htlc.amount_msat / 1000 >= real_dust_limit_timeout_sat {
+                                       addl_htlcs += 1;
+                               }
+                       }
+               }
+
+               // When calculating the set of HTLCs which will be included in their next commitment_signed, all
+               // non-dust inbound HTLCs are included (as all states imply it will be included) and only
+               // committed outbound HTLCs, see below.
+               let mut included_htlcs = 0;
+               for ref htlc in self.pending_inbound_htlcs.iter() {
+                       if htlc.amount_msat / 1000 <= real_dust_limit_timeout_sat {
+                               continue
+                       }
+                       included_htlcs += 1;
+               }
+
                for ref htlc in self.pending_outbound_htlcs.iter() {
-                       if htlc.amount_msat / 1000 <= self.counterparty_dust_limit_satoshis {
+                       if htlc.amount_msat / 1000 <= real_dust_limit_success_sat {
                                continue
                        }
-                       // We only include outbound HTLCs if it will not be included in their next
-                       // commitment_signed, i.e. if they've responded to us with an RAA after announcement.
+                       // We only include outbound HTLCs if it will not be included in their next commitment_signed,
+                       // i.e. if they've responded to us with an RAA after announcement.
                        match htlc.state {
-                               OutboundHTLCState::Committed => their_acked_htlcs += 1,
-                               OutboundHTLCState::RemoteRemoved {..} => their_acked_htlcs += 1,
+                               OutboundHTLCState::Committed => included_htlcs += 1,
+                               OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1,
+                               OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1,
                                _ => {},
                        }
                }
 
-               self.commit_tx_fee_msat(their_acked_htlcs + addl_htlcs)
+               let num_htlcs = included_htlcs + addl_htlcs;
+               let res = self.commit_tx_fee_msat(num_htlcs);
+               #[cfg(any(test, feature = "fuzztarget"))]
+               {
+                       let mut fee = res;
+                       if fee_spike_buffer_htlc.is_some() {
+                               fee = self.commit_tx_fee_msat(num_htlcs - 1);
+                       }
+                       let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
+                       let commitment_tx_info = CommitmentTxInfoCached {
+                               fee,
+                               total_pending_htlcs,
+                               next_holder_htlc_id: match htlc.origin {
+                                       HTLCInitiator::LocalOffered => self.next_holder_htlc_id + 1,
+                                       HTLCInitiator::RemoteOffered => self.next_holder_htlc_id,
+                               },
+                               next_counterparty_htlc_id: match htlc.origin {
+                                       HTLCInitiator::LocalOffered => self.next_counterparty_htlc_id,
+                                       HTLCInitiator::RemoteOffered => self.next_counterparty_htlc_id + 1,
+                               },
+                               feerate: self.feerate_per_kw,
+                       };
+                       *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info);
+               }
+               res
        }
 
        pub fn update_add_htlc<F, L: Deref>(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError>
@@ -1772,7 +1932,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 {
                        return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS)));
                }
-               let holder_max_htlc_value_in_flight_msat = Channel::<ChanSigner>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis);
+               let holder_max_htlc_value_in_flight_msat = Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis);
                if htlc_inbound_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat {
                        return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", holder_max_htlc_value_in_flight_msat)));
                }
@@ -1808,28 +1968,30 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                // Check that the remote can afford to pay for this HTLC on-chain at the current
                // feerate_per_kw, while maintaining their channel reserve (as required by the spec).
                let remote_commit_tx_fee_msat = if self.is_outbound() { 0 } else {
-                       // +1 for this HTLC.
-                       self.next_remote_commit_tx_fee_msat(1)
+                       let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
+                       self.next_remote_commit_tx_fee_msat(htlc_candidate, None) // Don't include the extra fee spike buffer HTLC in calculations
                };
                if pending_remote_value_msat - msg.amount_msat < remote_commit_tx_fee_msat {
                        return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
                };
 
                let chan_reserve_msat =
-                       Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
+                       Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
                if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < chan_reserve_msat {
                        return Err(ChannelError::Close("Remote HTLC add would put them under remote reserve value".to_owned()));
                }
 
                if !self.is_outbound() {
-                       // `+1` for this HTLC, `2 *` and `+1` fee spike buffer we keep for the remote. This deviates from the
-                       // spec because in the spec, the fee spike buffer requirement doesn't exist on the receiver's side,
-                       // only on the sender's.
-                       // Note that when we eventually remove support for fee updates and switch to anchor output fees,
-                       // we will drop the `2 *`, since we no longer be as sensitive to fee spikes. But, keep the extra +1
-                       // as we should still be able to afford adding this HTLC plus one more future HTLC, regardless of
-                       // being sensitive to fee spikes.
-                       let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(1 + 1);
+                       // `2 *` and `Some(())` is for the fee spike buffer we keep for the remote. This deviates from
+                       // the spec because in the spec, the fee spike buffer requirement doesn't exist on the
+                       // receiver's side, only on the sender's.
+                       // Note that when we eventually remove support for fee updates and switch to anchor output
+                       // fees, we will drop the `2 *`, since we no longer be as sensitive to fee spikes. But, keep
+                       // the extra htlc when calculating the next remote commitment transaction fee as we should
+                       // still be able to afford adding this HTLC plus one more future HTLC, regardless of being
+                       // sensitive to fee spikes.
+                       let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
+                       let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(htlc_candidate, Some(()));
                        if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat {
                                // Note that if the pending_forward_status is not updated here, then it's because we're already failing
                                // the HTLC, i.e. its status is already set to failing.
@@ -1838,9 +2000,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        }
                } else {
                        // Check that they won't violate our local required channel reserve by adding this HTLC.
-
-                       // +1 for this HTLC.
-                       let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(1);
+                       let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered);
+                       let local_commit_tx_fee_msat = self.next_local_commit_tx_fee_msat(htlc_candidate, None);
                        if self.value_to_self_msat < self.counterparty_selected_channel_reserve_satoshis * 1000 + local_commit_tx_fee_msat {
                                return Err(ChannelError::Close("Cannot accept HTLC that would put our balance under counterparty-announced channel reserve value".to_owned()));
                        }
@@ -1976,15 +2137,31 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        (commitment_tx.1, htlcs_cloned, commitment_tx.0, commitment_txid)
                };
 
+               let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
                //If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
                if update_fee {
-                       let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
-
-                       let counterparty_reserve_we_require = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
+                       let counterparty_reserve_we_require = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
                        if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require {
                                return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned())));
                        }
                }
+               #[cfg(any(test, feature = "fuzztarget"))]
+               {
+                       if self.is_outbound() {
+                               let projected_commit_tx_info = self.next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
+                               *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
+                               if let Some(info) = projected_commit_tx_info {
+                                       let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
+                                               + self.holding_cell_htlc_updates.len();
+                                       if info.total_pending_htlcs == total_pending_htlcs
+                                               && info.next_holder_htlc_id == self.next_holder_htlc_id
+                                               && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
+                                               && info.feerate == self.feerate_per_kw {
+                                                       assert_eq!(total_fee, info.fee / 1000);
+                                               }
+                               }
+                       }
+               }
 
                if msg.htlc_signatures.len() != num_htlcs {
                        return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), num_htlcs))));
@@ -2250,6 +2427,12 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        return Err(ChannelError::Close("Received an unexpected revoke_and_ack".to_owned()));
                }
 
+               #[cfg(any(test, feature = "fuzztarget"))]
+               {
+                       *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
+                       *self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
+               }
+
                self.commitment_secrets.provide_secret(self.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
                        .map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
                self.latest_monitor_update_id += 1;
@@ -2631,7 +2814,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
                        return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned()));
                }
-               Channel::<ChanSigner>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
+               Channel::<Signer>::check_remote_fee(fee_estimator, msg.feerate_per_kw)?;
                self.pending_update_fee = Some(msg.feerate_per_kw);
                self.update_time_counter += 1;
                Ok(())
@@ -3149,7 +3332,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        // channel might have been used to route very small values (either by honest users or as DoS).
                        self.channel_value_satoshis * 9 / 10,
 
-                       Channel::<ChanSigner>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
+                       Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
                );
        }
 
@@ -3184,7 +3367,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        }
 
        #[cfg(test)]
-       pub fn get_keys(&self) -> &ChanSigner {
+       pub fn get_keys(&self) -> &Signer {
                &self.holder_keys
        }
 
@@ -3478,8 +3661,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        funding_satoshis: self.channel_value_satoshis,
                        push_msat: self.channel_value_satoshis * 1000 - self.value_to_self_msat,
                        dust_limit_satoshis: self.holder_dust_limit_satoshis,
-                       max_htlc_value_in_flight_msat: Channel::<ChanSigner>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
-                       channel_reserve_satoshis: Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
+                       max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
+                       channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
                        htlc_minimum_msat: self.holder_htlc_minimum_msat,
                        feerate_per_kw: self.feerate_per_kw as u32,
                        to_self_delay: self.get_holder_selected_contest_delay(),
@@ -3512,8 +3695,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                msgs::AcceptChannel {
                        temporary_channel_id: self.channel_id,
                        dust_limit_satoshis: self.holder_dust_limit_satoshis,
-                       max_htlc_value_in_flight_msat: Channel::<ChanSigner>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
-                       channel_reserve_satoshis: Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
+                       max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis),
+                       channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
                        htlc_minimum_msat: self.holder_htlc_minimum_msat,
                        minimum_depth: self.minimum_depth,
                        to_self_delay: self.get_holder_selected_contest_delay(),
@@ -3720,11 +3903,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
 
                if !self.is_outbound() {
                        // Check that we won't violate the remote channel reserve by adding this HTLC.
-
                        let counterparty_balance_msat = self.channel_value_satoshis * 1000 - self.value_to_self_msat;
-                       let holder_selected_chan_reserve_msat = Channel::<ChanSigner>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
-                       // 1 additional HTLC corresponding to this HTLC.
-                       let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(1);
+                       let holder_selected_chan_reserve_msat = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis);
+                       let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered);
+                       let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None);
                        if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat {
                                return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned()));
                        }
@@ -3735,10 +3917,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat)));
                }
 
-               // The `+1` is for the HTLC currently being added to the commitment tx and
-               // the `2 *` and `+1` are for the fee spike buffer.
+               // `2 *` and extra HTLC are for the fee spike buffer.
                let commit_tx_fee_msat = if self.is_outbound() {
-                       2 * self.next_local_commit_tx_fee_msat(1 + 1)
+                       let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered);
+                       2 * self.next_local_commit_tx_fee_msat(htlc_candidate, Some(()))
                } else { 0 };
                if pending_value_to_self_msat - amount_msat < commit_tx_fee_msat {
                        return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", pending_value_to_self_msat, commit_tx_fee_msat)));
@@ -3881,6 +4063,24 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid();
                let (signature, htlc_signatures);
 
+               #[cfg(any(test, feature = "fuzztarget"))]
+               {
+                       if !self.is_outbound() {
+                               let projected_commit_tx_info = self.next_remote_commitment_tx_fee_info_cached.lock().unwrap().take();
+                               *self.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None;
+                               if let Some(info) = projected_commit_tx_info {
+                                       let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len();
+                                       if info.total_pending_htlcs == total_pending_htlcs
+                                               && info.next_holder_htlc_id == self.next_holder_htlc_id
+                                               && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
+                                               && info.feerate == self.feerate_per_kw {
+                                                       let actual_fee = self.commit_tx_fee_msat(counterparty_commitment_tx.1);
+                                                       assert_eq!(actual_fee, info.fee);
+                                               }
+                               }
+                       }
+               }
+
                {
                        let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.2.len());
                        for &(ref htlc, _) in counterparty_commitment_tx.2.iter() {
@@ -4055,7 +4255,7 @@ impl Readable for InboundHTLCRemovalReason {
        }
 }
 
-impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
+impl<Signer: Sign> Writeable for Channel<Signer> {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
                // Note that we write out as if remove_uncommitted_htlcs_and_mark_paused had just been
                // called but include holding cell updates (and obviously we don't modify self).
@@ -4072,7 +4272,13 @@ impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
 
                self.latest_monitor_update_id.write(writer)?;
 
-               self.holder_keys.write(writer)?;
+               let mut key_data = VecWriter(Vec::new());
+               self.holder_keys.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[..])?;
+
                self.shutdown_pubkey.write(writer)?;
                self.destination_script.write(writer)?;
 
@@ -4237,8 +4443,10 @@ impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
        }
 }
 
-impl<ChanSigner: ChannelKeys + Readable> Readable for Channel<ChanSigner> {
-       fn read<R : ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+const MAX_ALLOC_SIZE: usize = 64*1024;
+impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
+               where K::Target: KeysInterface<Signer = Signer> {
+       fn read<R : ::std::io::Read>(reader: &mut R, keys_source: &'a K) -> Result<Self, DecodeError> {
                let _ver: u8 = Readable::read(reader)?;
                let min_ver: u8 = Readable::read(reader)?;
                if min_ver > SERIALIZATION_VERSION {
@@ -4254,7 +4462,17 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for Channel<ChanSigner> {
 
                let latest_monitor_update_id = Readable::read(reader)?;
 
-               let holder_keys = 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 holder_keys = keys_source.read_chan_signer(&keys_data)?;
+
                let shutdown_pubkey = Readable::read(reader)?;
                let destination_script = Readable::read(reader)?;
 
@@ -4453,6 +4671,11 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for Channel<ChanSigner> {
                        commitment_secrets,
 
                        network_sync: UpdateStatus::Fresh,
+
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_local_commitment_tx_fee_info_cached: Mutex::new(None),
+                       #[cfg(any(test, feature = "fuzztarget"))]
+                       next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
                })
        }
 }
@@ -4469,17 +4692,17 @@ mod tests {
        use bitcoin::hashes::hex::FromHex;
        use hex;
        use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
-       use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys};
+       use ln::channel::{Channel,Sign,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,HTLCCandidate,HTLCInitiator,TxCreationKeys};
        use ln::channel::MAX_FUNDING_SATOSHIS;
        use ln::features::InitFeatures;
-       use ln::msgs::{OptionalField, DataLossProtect};
+       use ln::msgs::{OptionalField, DataLossProtect, DecodeError};
        use ln::chan_utils;
-       use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
+       use ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters, HTLC_SUCCESS_TX_WEIGHT, HTLC_TIMEOUT_TX_WEIGHT};
        use chain::chaininterface::{FeeEstimator,ConfirmationTarget};
-       use chain::keysinterface::{InMemoryChannelKeys, KeysInterface};
+       use chain::keysinterface::{InMemorySigner, KeysInterface};
        use chain::transaction::OutPoint;
        use util::config::UserConfig;
-       use util::enforcing_trait_impls::EnforcingChannelKeys;
+       use util::enforcing_trait_impls::EnforcingSigner;
        use util::test_utils;
        use util::logger::Logger;
        use bitcoin::secp256k1::{Secp256k1, Message, Signature, All};
@@ -4505,10 +4728,10 @@ mod tests {
        }
 
        struct Keys {
-               chan_keys: InMemoryChannelKeys,
+               chan_keys: InMemorySigner,
        }
        impl KeysInterface for Keys {
-               type ChanKeySigner = InMemoryChannelKeys;
+               type Signer = InMemorySigner;
 
                fn get_node_secret(&self) -> SecretKey { panic!(); }
                fn get_destination_script(&self) -> Script {
@@ -4524,10 +4747,11 @@ mod tests {
                        PublicKey::from_secret_key(&secp_ctx, &channel_close_key)
                }
 
-               fn get_channel_keys(&self, _inbound: bool, _channel_value_satoshis: u64) -> InMemoryChannelKeys {
+               fn get_channel_signer(&self, _inbound: bool, _channel_value_satoshis: u64) -> InMemorySigner {
                        self.chan_keys.clone()
                }
                fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
+               fn read_chan_signer(&self, _data: &[u8]) -> Result<Self::Signer, DecodeError> { panic!(); }
        }
 
        fn public_from_secret_hex(secp_ctx: &Secp256k1<All>, hex: &str) -> PublicKey {
@@ -4547,7 +4771,7 @@ mod tests {
 
                let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let node_a_chan = Channel::<EnforcingChannelKeys>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, 10000000, 100000, 42, &config).unwrap();
+               let node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, 10000000, 100000, 42, &config).unwrap();
 
                // Now change the fee so we can check that the fee in the open_channel message is the
                // same as the old fee.
@@ -4556,6 +4780,122 @@ mod tests {
                assert_eq!(open_channel_msg.feerate_per_kw, original_fee);
        }
 
+       #[test]
+       fn test_holder_vs_counterparty_dust_limit() {
+               // Test that when calculating the local and remote commitment transaction fees, the correct
+               // dust limits are used.
+               let feeest = TestFeeEstimator{fee_est: 15000};
+               let secp_ctx = Secp256k1::new();
+               let seed = [42; 32];
+               let network = Network::Testnet;
+               let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+
+               // Go through the flow of opening a channel between two nodes, making sure
+               // they have different dust limits.
+
+               // Create Node A's channel pointing to Node B's pubkey
+               let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+               let config = UserConfig::default();
+               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap();
+
+               // Create Node B's channel by receiving Node A's open_channel message
+               // Make sure A's dust limit is as we expect.
+               let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
+               assert_eq!(open_channel_msg.dust_limit_satoshis, 1560);
+               let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
+               let node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();
+
+               // Node B --> Node A: accept channel, explicitly setting B's dust limit.
+               let mut accept_channel_msg = node_b_chan.get_accept_channel();
+               accept_channel_msg.dust_limit_satoshis = 546;
+               node_a_chan.accept_channel(&accept_channel_msg, &config, InitFeatures::known()).unwrap();
+
+               // Put some inbound and outbound HTLCs in A's channel.
+               let htlc_amount_msat = 11_092_000; // put an amount below A's effective dust limit but above B's.
+               node_a_chan.pending_inbound_htlcs.push(InboundHTLCOutput {
+                       htlc_id: 0,
+                       amount_msat: htlc_amount_msat,
+                       payment_hash: PaymentHash(Sha256::hash(&[42; 32]).into_inner()),
+                       cltv_expiry: 300000000,
+                       state: InboundHTLCState::Committed,
+               });
+
+               node_a_chan.pending_outbound_htlcs.push(OutboundHTLCOutput {
+                       htlc_id: 1,
+                       amount_msat: htlc_amount_msat, // put an amount below A's dust amount but above B's.
+                       payment_hash: PaymentHash(Sha256::hash(&[43; 32]).into_inner()),
+                       cltv_expiry: 200000000,
+                       state: OutboundHTLCState::Committed,
+                       source: HTLCSource::OutboundRoute {
+                               path: Vec::new(),
+                               session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
+                               first_hop_htlc_msat: 548,
+                       }
+               });
+
+               // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
+               // the dust limit check.
+               let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
+               let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None);
+               let local_commit_fee_0_htlcs = node_a_chan.commit_tx_fee_msat(0);
+               assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs);
+
+               // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all
+               // of the HTLCs are seen to be above the dust limit.
+               node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false;
+               let remote_commit_fee_3_htlcs = node_a_chan.commit_tx_fee_msat(3);
+               let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered);
+               let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None);
+               assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs);
+       }
+
+       #[test]
+       fn test_timeout_vs_success_htlc_dust_limit() {
+               // Make sure that when `next_remote_commit_tx_fee_msat` and `next_local_commit_tx_fee_msat`
+               // calculate the real dust limits for HTLCs (i.e. the dust limit given by the counterparty
+               // *plus* the fees paid for the HTLC) they don't swap `HTLC_SUCCESS_TX_WEIGHT` for
+               // `HTLC_TIMEOUT_TX_WEIGHT`, and vice versa.
+               let fee_est = TestFeeEstimator{fee_est: 253 };
+               let secp_ctx = Secp256k1::new();
+               let seed = [42; 32];
+               let network = Network::Testnet;
+               let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
+
+               let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
+               let config = UserConfig::default();
+               let mut chan = Channel::<EnforcingSigner>::new_outbound(&&fee_est, &&keys_provider, node_id, 10000000, 100000, 42, &config).unwrap();
+
+               let commitment_tx_fee_0_htlcs = chan.commit_tx_fee_msat(0);
+               let commitment_tx_fee_1_htlc = chan.commit_tx_fee_msat(1);
+
+               // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be
+               // counted as dust when it shouldn't be.
+               let htlc_amt_above_timeout = ((253 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + chan.holder_dust_limit_satoshis + 1) * 1000;
+               let htlc_candidate = HTLCCandidate::new(htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
+               let commitment_tx_fee = chan.next_local_commit_tx_fee_msat(htlc_candidate, None);
+               assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
+
+               // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
+               let dust_htlc_amt_below_success = ((253 * HTLC_SUCCESS_TX_WEIGHT / 1000) + chan.holder_dust_limit_satoshis - 1) * 1000;
+               let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_below_success, HTLCInitiator::RemoteOffered);
+               let commitment_tx_fee = chan.next_local_commit_tx_fee_msat(htlc_candidate, None);
+               assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
+
+               chan.channel_transaction_parameters.is_outbound_from_holder = false;
+
+               // If swapped: this HTLC would be counted as non-dust when it shouldn't be.
+               let dust_htlc_amt_above_timeout = ((253 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + chan.counterparty_dust_limit_satoshis + 1) * 1000;
+               let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_above_timeout, HTLCInitiator::LocalOffered);
+               let commitment_tx_fee = chan.next_remote_commit_tx_fee_msat(htlc_candidate, None);
+               assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs);
+
+               // If swapped: this HTLC would be counted as dust when it shouldn't be.
+               let htlc_amt_below_success = ((253 * HTLC_SUCCESS_TX_WEIGHT / 1000) + chan.counterparty_dust_limit_satoshis - 1) * 1000;
+               let htlc_candidate = HTLCCandidate::new(htlc_amt_below_success, HTLCInitiator::RemoteOffered);
+               let commitment_tx_fee = chan.next_remote_commit_tx_fee_msat(htlc_candidate, None);
+               assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc);
+       }
+
        #[test]
        fn channel_reestablish_no_updates() {
                let feeest = TestFeeEstimator{fee_est: 15000};
@@ -4570,12 +4910,12 @@ mod tests {
                // Create Node A's channel pointing to Node B's pubkey
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let config = UserConfig::default();
-               let mut node_a_chan = Channel::<EnforcingChannelKeys>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap();
+               let mut node_a_chan = Channel::<EnforcingSigner>::new_outbound(&&feeest, &&keys_provider, node_b_node_id, 10000000, 100000, 42, &config).unwrap();
 
                // Create Node B's channel by receiving Node A's open_channel message
                let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash());
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
-               let mut node_b_chan = Channel::<EnforcingChannelKeys>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();
+               let mut node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, InitFeatures::known(), &open_channel_msg, 7, &config).unwrap();
 
                // Node B --> Node A: accept channel
                let accept_channel_msg = node_b_chan.get_accept_channel();
@@ -4627,7 +4967,7 @@ mod tests {
                let logger : Arc<Logger> = Arc::new(test_utils::TestLogger::new());
                let secp_ctx = Secp256k1::new();
 
-               let mut chan_keys = InMemoryChannelKeys::new(
+               let mut chan_keys = InMemorySigner::new(
                        &secp_ctx,
                        SecretKey::from_slice(&hex::decode("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
                        SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
@@ -4638,7 +4978,7 @@ mod tests {
                        // These aren't set in the test vectors:
                        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
                        10_000_000,
-                       (0, 0)
+                       [0; 32]
                );
 
                assert_eq!(chan_keys.pubkeys().funding_pubkey.serialize()[..],
@@ -4648,7 +4988,7 @@ mod tests {
                let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
                let mut config = UserConfig::default();
                config.channel_options.announced_channel = false;
-               let mut chan = Channel::<InMemoryChannelKeys>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, 10_000_000, 100000, 42, &config).unwrap(); // Nothing uses their network key in this test
+               let mut chan = Channel::<InMemorySigner>::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, 10_000_000, 100000, 42, &config).unwrap(); // Nothing uses their network key in this test
                chan.holder_dust_limit_satoshis = 546;
 
                let funding_info = OutPoint{ txid: Txid::from_hex("8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be").unwrap(), index: 0 };
@@ -4723,15 +5063,13 @@ mod tests {
                                        &chan.holder_keys.pubkeys().funding_pubkey,
                                        chan.counterparty_funding_pubkey()
                                );
-                               let holder_sig = chan_keys.sign_holder_commitment(&holder_commitment_tx, &secp_ctx).unwrap();
+                               let (holder_sig, htlc_sigs) = chan_keys.sign_holder_commitment_and_htlcs(&holder_commitment_tx, &secp_ctx).unwrap();
                                assert_eq!(Signature::from_der(&hex::decode($sig_hex).unwrap()[..]).unwrap(), holder_sig, "holder_sig");
 
                                let funding_redeemscript = chan.get_funding_redeemscript();
                                let tx = holder_commitment_tx.add_holder_sig(&funding_redeemscript, holder_sig);
                                assert_eq!(serialize(&tx)[..], hex::decode($tx_hex).unwrap()[..], "tx");
 
-                               let htlc_sigs = chan_keys.sign_holder_commitment_htlc_transactions(&holder_commitment_tx, &secp_ctx).unwrap();
-
                                // ((htlc, counterparty_sig), (index, holder_sig))
                                let mut htlc_sig_iter = holder_commitment_tx.htlcs().iter().zip(&holder_commitment_tx.counterparty_htlc_sigs).zip(htlc_sigs.iter().enumerate());