]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Merge pull request #1169 from TheBlueMatt/2021-11-fix-update-announcements
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Thu, 9 Dec 2021 18:21:55 +0000 (18:21 +0000)
committerGitHub <noreply@github.com>
Thu, 9 Dec 2021 18:21:55 +0000 (18:21 +0000)
Fix announcements of our own gossip

1  2 
lightning/src/ln/channel.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/msgs.rs

index a027e6c364734ded0b61ad1c24e1b72e26eaede0,55dd76cc033faee51a13dad560f6ce64595db858..0cdcb0c14c2b0665f45c272e244f714208e29001
@@@ -387,9 -387,9 +387,9 @@@ pub(super) struct MonitorRestoreUpdate
  /// the channel. Sadly, there isn't really a good number for this - if we expect to have no new
  /// HTLCs for days we may need this to suffice for feerate increases across days, but that may
  /// leave the channel less usable as we hold a bigger reserve.
 -#[cfg(fuzzing)]
 +#[cfg(any(fuzzing, test))]
  pub const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2;
 -#[cfg(not(fuzzing))]
 +#[cfg(not(any(fuzzing, test)))]
  const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2;
  
  /// If we fail to see a funding transaction confirmed on-chain within this many blocks after the
@@@ -481,9 -481,14 +481,14 @@@ pub(super) struct Channel<Signer: Sign
        holding_cell_update_fee: Option<u32>,
        next_holder_htlc_id: u64,
        next_counterparty_htlc_id: u64,
-       update_time_counter: u32,
        feerate_per_kw: u32,
  
+       /// The timestamp set on our latest `channel_update` message for this channel. It is updated
+       /// when the channel is updated in ways which may impact the `channel_update` message or when a
+       /// new block is received, ensuring it's always at least moderately close to the current real
+       /// time.
+       update_time_counter: u32,
        #[cfg(debug_assertions)]
        /// Max to_local and to_remote outputs in a locally-generated commitment transaction
        holder_max_commitment_tx_output: Mutex<(u64, u64)>,
        channel_creation_height: u32,
  
        counterparty_dust_limit_satoshis: u64,
 +
        #[cfg(test)]
        pub(super) holder_dust_limit_satoshis: u64,
        #[cfg(not(test))]
        holder_dust_limit_satoshis: u64,
 +
        #[cfg(test)]
        pub(super) counterparty_max_htlc_value_in_flight_msat: u64,
        #[cfg(not(test))]
        counterparty_max_htlc_value_in_flight_msat: u64,
 -      //get_holder_max_htlc_value_in_flight_msat(): u64,
 +
 +      #[cfg(test)]
 +      pub(super) holder_max_htlc_value_in_flight_msat: u64,
 +      #[cfg(not(test))]
 +      holder_max_htlc_value_in_flight_msat: u64,
 +
        /// minimum channel reserve for self to maintain - set by them.
        counterparty_selected_channel_reserve_satoshis: Option<u64>,
 -      // get_holder_selected_channel_reserve_satoshis(channel_value_sats: u64): u64
 +
 +      #[cfg(test)]
 +      pub(super) holder_selected_channel_reserve_satoshis: u64,
 +      #[cfg(not(test))]
 +      holder_selected_channel_reserve_satoshis: u64,
 +
        counterparty_htlc_minimum_msat: u64,
        holder_htlc_minimum_msat: u64,
        #[cfg(test)]
@@@ -691,10 -684,6 +696,10 @@@ impl<Signer: Sign> Channel<Signer> 
        /// required by us.
        ///
        /// Guaranteed to return a value no larger than channel_value_satoshis
 +      ///
 +      /// This is used both for new channels and to figure out what reserve value we sent to peers
 +      /// for channels serialized before we included our selected reserve value in the serialized
 +      /// data explicitly.
        pub(crate) fn get_holder_selected_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 {
                let (q, _) = channel_value_satoshis.overflowing_div(100);
                cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO
                        counterparty_dust_limit_satoshis: 0,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: 0,
 +                      holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis),
                        counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
 +                      holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: 0,
                        holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
                        counterparty_max_accepted_htlcs: 0,
                where F::Target: FeeEstimator
        {
                let lower_limit = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
 -              if feerate_per_kw < lower_limit {
 -                      return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {}", feerate_per_kw, lower_limit)));
 +              // Some fee estimators round up to the next full sat/vbyte (ie 250 sats per kw), causing
 +              // occasional issues with feerate disagreements between an initiator that wants a feerate
 +              // of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250
 +              // sat/kw before the comparison here.
 +              if feerate_per_kw + 250 < lower_limit {
 +                      return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {} (- 250)", feerate_per_kw, lower_limit)));
                }
                // We only bound the fee updates on the upper side to prevent completely absurd feerates,
                // always accepting up to 25 sat/vByte or 10x our fee estimator's "High Priority" fee.
  
        /// 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>(
 +      pub fn new_from_req<K: Deref, F: Deref, L: Deref>(
                fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures,
 -              msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32
 +              msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L
        ) -> Result<Channel<Signer>, ChannelError>
                where K::Target: KeysInterface<Signer = Signer>,
 -          F::Target: FeeEstimator
 +                    F::Target: FeeEstimator,
 +                    L::Target: Logger,
        {
                // First check the channel type is known, failing before we do anything else if we don't
                // support this channel type.
                if msg.dust_limit_satoshis > msg.funding_satoshis {
                        return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis)));
                }
 -              if msg.dust_limit_satoshis > msg.channel_reserve_satoshis {
 -                      return Err(ChannelError::Close(format!("Bogus; channel reserve ({}) is less than dust limit ({})", msg.channel_reserve_satoshis, msg.dust_limit_satoshis)));
 -              }
                let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
                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)));
                        return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
                }
                if msg.channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is smaller than our dust limit ({})", msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
 +                      log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.",
 +                              msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
                }
                if holder_selected_channel_reserve_satoshis < msg.dust_limit_satoshis {
                        return Err(ChannelError::Close(format!("Dust limit ({}) too high for the channel reserve we require the remote to keep ({})", msg.dust_limit_satoshis, holder_selected_channel_reserve_satoshis)));
                        counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
                        holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
                        counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
 +                      holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis),
                        counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
 +                      holder_selected_channel_reserve_satoshis,
                        counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
                        holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
                        counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
                        };
                        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.unwrap() 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::<Signer>::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 >= self.holder_selected_channel_reserve_satoshis as i64);
                        broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64);
                }
  
                if msg.channel_reserve_satoshis > self.channel_value_satoshis {
                        return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.channel_value_satoshis)));
                }
 -              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::<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)));
 +              if msg.dust_limit_satoshis > self.holder_selected_channel_reserve_satoshis {
 +                      return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.holder_selected_channel_reserve_satoshis)));
                }
                let full_channel_value_msat = (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000;
                if msg.htlc_minimum_msat >= full_channel_value_msat {
        /// Doesn't bother handling the
        /// if-we-removed-it-already-but-haven't-fully-resolved-they-can-still-send-an-inbound-HTLC
        /// corner case properly.
 +      /// The channel reserve is subtracted from each balance.
 +      /// See also [`Channel::get_balance_msat`]
        pub fn get_inbound_outbound_available_balance_msat(&self) -> (u64, u64) {
                // Note that we have to handle overflow due to the above case.
                (
                        cmp::max(self.channel_value_satoshis as i64 * 1000
                                - self.value_to_self_msat as i64
                                - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
 -                              - Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000,
 +                              - self.holder_selected_channel_reserve_satoshis as i64 * 1000,
                        0) as u64,
                        cmp::max(self.value_to_self_msat as i64
                                - self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64
                )
        }
  
 +      /// Get our total balance in msat.
 +      /// This is the amount that would go to us if we close the channel, ignoring any on-chain fees.
 +      /// See also [`Channel::get_inbound_outbound_available_balance_msat`]
 +      pub fn get_balance_msat(&self) -> u64 {
 +              self.value_to_self_msat
 +                      - self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat
 +      }
 +
        pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option<u64>) {
 -              (Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis),
 -              self.counterparty_selected_channel_reserve_satoshis)
 +              (self.holder_selected_channel_reserve_satoshis, self.counterparty_selected_channel_reserve_satoshis)
        }
  
        // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs.
                if inbound_stats.pending_htlcs + 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::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis);
 -              if inbound_stats.pending_htlcs_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)));
 +              if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat {
 +                      return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat)));
                }
                // Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet
                // the reserve_satoshis we told them to always have as direct payment so that they lose
                        return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned()));
                };
  
 -              let chan_reserve_msat =
 -                      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 {
 +              if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < self.holder_selected_channel_reserve_satoshis * 1000 {
                        return Err(ChannelError::Close("Remote HTLC add would put them under remote reserve value".to_owned()));
                }
  
                        // 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 {
 +                      if pending_remote_value_msat - msg.amount_msat - self.holder_selected_channel_reserve_satoshis * 1000 < 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.
                                log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", log_bytes!(self.channel_id()));
                } else { false };
                if update_fee {
                        debug_assert!(!self.is_outbound());
 -                      let counterparty_reserve_we_require_msat = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
 +                      let counterparty_reserve_we_require_msat = self.holder_selected_channel_reserve_satoshis * 1000;
                        if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat {
                                return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned())));
                        }
                        // channel might have been used to route very small values (either by honest users or as DoS).
                        self.channel_value_satoshis * 1000 * 9 / 10,
  
 -                      Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
 +                      self.holder_max_htlc_value_in_flight_msat
                );
        }
  
        }
  
        pub fn set_channel_update_status(&mut self, status: ChannelUpdateStatus) {
+               self.update_time_counter += 1;
                self.channel_update_status = status;
        }
  
                        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::<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),
 +                      max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
 +                      channel_reserve_satoshis: self.holder_selected_channel_reserve_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(),
                msgs::AcceptChannel {
                        temporary_channel_id: self.channel_id,
                        dust_limit_satoshis: self.holder_dust_limit_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),
 +                      max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat,
 +                      channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis,
                        htlc_minimum_msat: self.holder_htlc_minimum_msat,
                        minimum_depth: self.minimum_depth.unwrap(),
                        to_self_delay: self.get_holder_selected_contest_delay(),
                        // Check that we won't violate the remote channel reserve by adding this HTLC.
                        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);
 -                      let holder_selected_chan_reserve_msat = Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000;
 +                      let holder_selected_chan_reserve_msat = self.holder_selected_channel_reserve_satoshis * 1000;
                        if commitment_stats.remote_balance_msat < counterparty_commit_tx_fee_msat + holder_selected_chan_reserve_msat {
                                return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned()));
                        }
@@@ -5393,15 -5374,6 +5399,15 @@@ impl<Signer: Sign> Writeable for Channe
                let chan_type = if self.channel_type != ChannelTypeFeatures::only_static_remote_key() {
                        Some(&self.channel_type) } else { None };
  
 +              // The same logic applies for `holder_selected_channel_reserve_satoshis` and
 +              // `holder_max_htlc_value_in_flight_msat` values other than the defaults.
 +              let serialized_holder_selected_reserve =
 +                      if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis)
 +                      { Some(self.holder_selected_channel_reserve_satoshis) } else { None };
 +              let serialized_holder_htlc_max_in_flight =
 +                      if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis)
 +                      { Some(self.holder_max_htlc_value_in_flight_msat) } else { None };
 +
                write_tlv_fields!(writer, {
                        (0, self.announcement_sigs, option),
                        // minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
                        (1, self.minimum_depth, option),
                        (2, chan_type, option),
                        (3, self.counterparty_selected_channel_reserve_satoshis, option),
 +                      (4, serialized_holder_selected_reserve, option),
                        (5, self.config, required),
 +                      (6, serialized_holder_htlc_max_in_flight, option),
                        (7, self.shutdown_scriptpubkey, option),
                        (9, self.target_closing_feerate_sats_per_kw, option),
                        (11, self.monitor_pending_finalized_fulfills, vec_type),
@@@ -5655,8 -5625,6 +5661,8 @@@ impl<'a, Signer: Sign, K: Deref> Readab
                let mut announcement_sigs = None;
                let mut target_closing_feerate_sats_per_kw = None;
                let mut monitor_pending_finalized_fulfills = Some(Vec::new());
 +              let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis));
 +              let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis));
                // Prior to supporting channel type negotiation, all of our channels were static_remotekey
                // only, so we default to that if none was written.
                let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
                        (1, minimum_depth, option),
                        (2, channel_type, option),
                        (3, counterparty_selected_channel_reserve_satoshis, option),
 +                      (4, holder_selected_channel_reserve_satoshis, option),
                        (5, config, option), // Note that if none is provided we will *not* overwrite the existing one.
 +                      (6, holder_max_htlc_value_in_flight_msat, option),
                        (7, shutdown_scriptpubkey, option),
                        (9, target_closing_feerate_sats_per_kw, option),
                        (11, monitor_pending_finalized_fulfills, vec_type),
                        counterparty_dust_limit_satoshis,
                        holder_dust_limit_satoshis,
                        counterparty_max_htlc_value_in_flight_msat,
 +                      holder_max_htlc_value_in_flight_msat: holder_max_htlc_value_in_flight_msat.unwrap(),
                        counterparty_selected_channel_reserve_satoshis,
 +                      holder_selected_channel_reserve_satoshis: holder_selected_channel_reserve_satoshis.unwrap(),
                        counterparty_htlc_minimum_msat,
                        holder_htlc_minimum_msat,
                        counterparty_max_accepted_htlcs,
@@@ -5933,7 -5897,6 +5939,7 @@@ mod tests 
                let seed = [42; 32];
                let network = Network::Testnet;
                let keys_provider = test_utils::TestKeysInterface::new(&seed, network);
 +              let logger = test_utils::TestLogger::new();
  
                // Go through the flow of opening a channel between two nodes, making sure
                // they have different dust limits.
                // 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());
                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, 0).unwrap();
 +              let node_b_chan = Channel::<EnforcingSigner>::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap();
  
                // Node B --> Node A: accept channel, explicitly setting B's dust limit.
                let mut accept_channel_msg = node_b_chan.get_accept_channel();
                // Create Node B's channel by receiving Node A's open_channel message
                let open_channel_msg = node_a_chan.get_open_channel(chain_hash);
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).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, 0).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, 0, &&logger).unwrap();
  
                // Node B --> Node A: accept channel
                let accept_channel_msg = node_b_chan.get_accept_channel();
index 3a30cb7f1d05bd4c47aca455052e252f14ac0d10,af54f9f8d29d7fbfa8eab19164c45d5886473949..86b60ba3a49f8b2e2c75cf0a3002413c471f1591
@@@ -18,7 -18,7 +18,7 @@@ use chain::channelmonitor::{ChannelMoni
  use chain::transaction::OutPoint;
  use chain::keysinterface::BaseSign;
  use ln::{PaymentPreimage, PaymentSecret, PaymentHash};
 -use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, MIN_AFFORDABLE_HTLC_COUNT};
 +use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
  use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, PaymentId, RAACommitmentOrder, PaymentSendFailure, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
  use ln::channel::{Channel, ChannelError};
  use ln::{chan_utils, onion_utils};
@@@ -42,6 -42,9 +42,6 @@@ use bitcoin::blockdata::opcodes
  use bitcoin::blockdata::constants::genesis_block;
  use bitcoin::network::constants::Network;
  
 -use bitcoin::hashes::sha256::Hash as Sha256;
 -use bitcoin::hashes::Hash;
 -
  use bitcoin::secp256k1::Secp256k1;
  use bitcoin::secp256k1::key::{PublicKey,SecretKey};
  
@@@ -105,6 -108,8 +105,6 @@@ fn test_insane_channel_opens() 
  
        insane_open_helper("Peer never wants payout outputs?", |mut msg| { msg.dust_limit_satoshis = msg.funding_satoshis + 1 ; msg });
  
 -      insane_open_helper(r"Bogus; channel reserve \(\d+\) is less than dust limit \(\d+\)", |mut msg| { msg.dust_limit_satoshis = msg.channel_reserve_satoshis + 1; msg });
 -
        insane_open_helper(r"Minimum htlc value \(\d+\) was larger than full channel value \(\d+\)", |mut msg| { msg.htlc_minimum_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000; msg });
  
        insane_open_helper("They wanted our payments to be delayed by a needlessly long period", |mut msg| { msg.to_self_delay = MAX_LOCAL_BREAKDOWN_TIMEOUT + 1; msg });
        insane_open_helper("max_accepted_htlcs was 484. It must not be larger than 483", |mut msg| { msg.max_accepted_htlcs = 484; msg });
  }
  
 +fn do_test_counterparty_no_reserve(send_from_initiator: bool) {
 +      // A peer providing a channel_reserve_satoshis of 0 (or less than our dust limit) is insecure,
 +      // but only for them. Because some LSPs do it with some level of trust of the clients (for a
 +      // substantial UX improvement), we explicitly allow it. Because it's unlikely to happen often
 +      // in normal testing, we test it explicitly here.
 +      let chanmon_cfgs = create_chanmon_cfgs(2);
 +      let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
 +      let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
 +      let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 +
 +      // Have node0 initiate a channel to node1 with aforementioned parameters
 +      let mut push_amt = 100_000_000;
 +      let feerate_per_kw = 253;
 +      push_amt -= feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + 4 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000;
 +      push_amt -= Channel::<EnforcingSigner>::get_holder_selected_channel_reserve_satoshis(100_000) * 1000;
 +
 +      let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, if send_from_initiator { 0 } else { push_amt }, 42, None).unwrap();
 +      let mut open_channel_message = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 +      if !send_from_initiator {
 +              open_channel_message.channel_reserve_satoshis = 0;
 +              open_channel_message.max_htlc_value_in_flight_msat = 100_000_000;
 +      }
 +      nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel_message);
 +
 +      // Extract the channel accept message from node1 to node0
 +      let mut accept_channel_message = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
 +      if send_from_initiator {
 +              accept_channel_message.channel_reserve_satoshis = 0;
 +              accept_channel_message.max_htlc_value_in_flight_msat = 100_000_000;
 +      }
 +      nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel_message);
 +      {
 +              let mut lock;
 +              let mut chan = get_channel_ref!(if send_from_initiator { &nodes[1] } else { &nodes[0] }, lock, temp_channel_id);
 +              chan.holder_selected_channel_reserve_satoshis = 0;
 +              chan.holder_max_htlc_value_in_flight_msat = 100_000_000;
 +      }
 +
 +      let funding_tx = sign_funding_transaction(&nodes[0], &nodes[1], 100_000, temp_channel_id);
 +      let funding_msgs = create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &funding_tx);
 +      create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &funding_msgs.0);
 +
 +      // nodes[0] should now be able to send the full balance to nodes[1], violating nodes[1]'s
 +      // security model if it ever tries to send funds back to nodes[0] (but that's not our problem).
 +      if send_from_initiator {
 +              send_payment(&nodes[0], &[&nodes[1]], 100_000_000
 +                      // Note that for outbound channels we have to consider the commitment tx fee and the
 +                      // "fee spike buffer", which is currently a multiple of the total commitment tx fee as
 +                      // well as an additional HTLC.
 +                      - FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * commit_tx_fee_msat(feerate_per_kw, 2));
 +      } else {
 +              send_payment(&nodes[1], &[&nodes[0]], push_amt);
 +      }
 +}
 +
 +#[test]
 +fn test_counterparty_no_reserve() {
 +      do_test_counterparty_no_reserve(true);
 +      do_test_counterparty_no_reserve(false);
 +}
 +
  #[test]
  fn test_async_inbound_update_fee() {
        let chanmon_cfgs = create_chanmon_cfgs(2);
@@@ -7145,7 -7089,7 +7145,7 @@@ fn test_user_configurable_csv_delay() 
        nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
 -      if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &low_our_to_self_config, 0) {
 +      if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &low_our_to_self_config, 0, &nodes[0].logger) {
                match error {
                        ChannelError::Close(err) => { assert!(regex::Regex::new(r"Configured with an unreasonable our_to_self_delay \(\d+\) putting user funds at risks").unwrap().is_match(err.as_str()));  },
                        _ => panic!("Unexpected event"),
        nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 1000000, 1000000, 42, None).unwrap();
        let mut open_channel = get_event_msg!(nodes[1], MessageSendEvent::SendOpenChannel, nodes[0].node.get_our_node_id());
        open_channel.to_self_delay = 200;
 -      if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &high_their_to_self_config, 0) {
 +      if let Err(error) = Channel::new_from_req(&&test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, &nodes[0].keys_manager, nodes[1].node.get_our_node_id(), &InitFeatures::known(), &open_channel, 0, &high_their_to_self_config, 0, &nodes[0].logger) {
                match error {
                        ChannelError::Close(err) => { assert!(regex::Regex::new(r"They wanted our payments to be delayed by a needlessly long period\. Upper limit: \d+\. Actual: \d+").unwrap().is_match(err.as_str())); },
                        _ => panic!("Unexpected event"),
@@@ -7369,9 -7313,9 +7369,9 @@@ fn test_announce_disable_channels() 
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
  
-       let short_id_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
-       let short_id_2 = create_announced_chan_between_nodes(&nodes, 1, 0, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
-       let short_id_3 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()).0.contents.short_channel_id;
+       create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+       create_announced_chan_between_nodes(&nodes, 1, 0, InitFeatures::known(), InitFeatures::known());
+       create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
  
        // Disconnect peers
        nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
        nodes[0].node.timer_tick_occurred(); // DisabledStaged -> Disabled
        let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(msg_events.len(), 3);
-       let mut chans_disabled: HashSet<u64> = [short_id_1, short_id_2, short_id_3].iter().map(|a| *a).collect();
+       let mut chans_disabled = HashMap::new();
        for e in msg_events {
                match e {
                        MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                                assert_eq!(msg.contents.flags & (1<<1), 1<<1); // The "channel disabled" bit should be set
                                // Check that each channel gets updated exactly once
-                               if !chans_disabled.remove(&msg.contents.short_channel_id) {
+                               if chans_disabled.insert(msg.contents.short_channel_id, msg.contents.timestamp).is_some() {
                                        panic!("Generated ChannelUpdate for wrong chan!");
                                }
                        },
        nodes[0].node.timer_tick_occurred();
        let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
        assert_eq!(msg_events.len(), 3);
-       chans_disabled = [short_id_1, short_id_2, short_id_3].iter().map(|a| *a).collect();
        for e in msg_events {
                match e {
                        MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
                                assert_eq!(msg.contents.flags & (1<<1), 0); // The "channel disabled" bit should be off
-                               // Check that each channel gets updated exactly once
-                               if !chans_disabled.remove(&msg.contents.short_channel_id) {
-                                       panic!("Generated ChannelUpdate for wrong chan!");
+                               match chans_disabled.remove(&msg.contents.short_channel_id) {
+                                       // Each update should have a higher timestamp than the previous one, replacing
+                                       // the old one.
+                                       Some(prev_timestamp) => assert!(msg.contents.timestamp > prev_timestamp),
+                                       None => panic!("Generated ChannelUpdate for wrong chan!"),
                                }
                        },
                        _ => panic!("Unexpected event"),
                }
        }
+       // Check that each channel gets updated exactly once
+       assert!(chans_disabled.is_empty());
  }
  
  #[test]
diff --combined lightning/src/ln/msgs.rs
index 3c6300ef8eadc5e517c3fb398c021bba8c53dd31,9662ffa7d48078f33eef4516f26ce8ffcb7d11d9..39c00105f8d675e5cf5ce664b2d7416654c40cfb
@@@ -394,10 -394,12 +394,10 @@@ pub enum NetAddress 
                port: u16,
        },
        /// An old-style Tor onion address/port on which the peer is listening.
 -      OnionV2 {
 -              /// The bytes (usually encoded in base32 with ".onion" appended)
 -              addr: [u8; 10],
 -              /// The port on which the node is listening
 -              port: u16,
 -      },
 +      ///
 +      /// This field is deprecated and the Tor network generally no longer supports V2 Onion
 +      /// addresses. Thus, the details are not parsed here.
 +      OnionV2([u8; 12]),
        /// A new-style Tor onion address/port on which the peer is listening.
        /// To create the human-readable "hostname", concatenate ed25519_pubkey, checksum, and version,
        /// wrap as base32 and append ".onion".
@@@ -419,7 -421,7 +419,7 @@@ impl NetAddress 
                match self {
                        &NetAddress::IPv4 {..} => { 1 },
                        &NetAddress::IPv6 {..} => { 2 },
 -                      &NetAddress::OnionV2 {..} => { 3 },
 +                      &NetAddress::OnionV2(_) => { 3 },
                        &NetAddress::OnionV3 {..} => { 4 },
                }
        }
                match self {
                        &NetAddress::IPv4 { .. } => { 6 },
                        &NetAddress::IPv6 { .. } => { 18 },
 -                      &NetAddress::OnionV2 { .. } => { 12 },
 +                      &NetAddress::OnionV2(_) => { 12 },
                        &NetAddress::OnionV3 { .. } => { 37 },
                }
        }
@@@ -451,9 -453,10 +451,9 @@@ impl Writeable for NetAddress 
                                addr.write(writer)?;
                                port.write(writer)?;
                        },
 -                      &NetAddress::OnionV2 { ref addr, ref port } => {
 +                      &NetAddress::OnionV2(bytes) => {
                                3u8.write(writer)?;
 -                              addr.write(writer)?;
 -                              port.write(writer)?;
 +                              bytes.write(writer)?;
                        },
                        &NetAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
                                4u8.write(writer)?;
@@@ -483,7 -486,12 +483,7 @@@ impl Readable for Result<NetAddress, u8
                                        port: Readable::read(reader)?,
                                }))
                        },
 -                      3 => {
 -                              Ok(Ok(NetAddress::OnionV2 {
 -                                      addr: Readable::read(reader)?,
 -                                      port: Readable::read(reader)?,
 -                              }))
 -                      },
 +                      3 => Ok(Ok(NetAddress::OnionV2(Readable::read(reader)?))),
                        4 => {
                                Ok(Ok(NetAddress::OnionV3 {
                                        ed25519_pubkey: Readable::read(reader)?,
@@@ -707,6 -715,10 +707,10 @@@ pub enum ErrorAction 
        /// The peer did something harmless that we weren't able to meaningfully process.
        /// If the error is logged, log it at the given level.
        IgnoreAndLog(logger::Level),
+       /// The peer provided us with a gossip message which we'd already seen. In most cases this
+       /// should be ignored, but it may result in the message being forwarded if it is a duplicate of
+       /// our own channel announcements.
+       IgnoreDuplicateGossip,
        /// The peer did something incorrect. Tell them.
        SendErrorMessage {
                /// The message to send.
@@@ -1914,9 -1926,10 +1918,9 @@@ mod tests 
                        });
                }
                if onionv2 {
 -                      addresses.push(msgs::NetAddress::OnionV2 {
 -                              addr: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246],
 -                              port: 9735
 -                      });
 +                      addresses.push(msgs::NetAddress::OnionV2(
 +                              [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
 +                      ));
                }
                if onionv3 {
                        addresses.push(msgs::NetAddress::OnionV3 {