X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=a9e7ffab4eb8719c0e6096a0ee98630747242ecb;hb=25c1ad8e1918ee985f39b2df8714df96cad2eae6;hp=e5452d54fae91d287d69648ba5715b73cbc6dd44;hpb=3ff94fae55a155603ddcb7c2a96d3b36a0eefa63;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index e5452d54..a9e7ffab 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1368,413 +1368,839 @@ impl ChannelContext { pub fn counterparty_forwarding_info(&self) -> Option { self.counterparty_forwarding_info.clone() } -} - -// Internal utility functions for channels - -/// Returns the value to use for `holder_max_htlc_value_in_flight_msat` as a percentage of the -/// `channel_value_satoshis` in msat, set through -/// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`] -/// -/// The effective percentage is lower bounded by 1% and upper bounded by 100%. -/// -/// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]: crate::util::config::ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel -fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64, config: &ChannelHandshakeConfig) -> u64 { - let configured_percent = if config.max_inbound_htlc_value_in_flight_percent_of_channel < 1 { - 1 - } else if config.max_inbound_htlc_value_in_flight_percent_of_channel > 100 { - 100 - } else { - config.max_inbound_htlc_value_in_flight_percent_of_channel as u64 - }; - channel_value_satoshis * 10 * configured_percent -} -/// Returns a minimum channel reserve value the remote needs to maintain, -/// required by us according to the configured or default -/// [`ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`] -/// -/// Guaranteed to return a value no larger than channel_value_satoshis -/// -/// This is used both for outbound and inbound channels and has lower bound -/// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`. -pub(crate) fn get_holder_selected_channel_reserve_satoshis(channel_value_satoshis: u64, config: &UserConfig) -> u64 { - let calculated_reserve = channel_value_satoshis.saturating_mul(config.channel_handshake_config.their_channel_reserve_proportional_millionths as u64) / 1_000_000; - cmp::min(channel_value_satoshis, cmp::max(calculated_reserve, MIN_THEIR_CHAN_RESERVE_SATOSHIS)) -} + /// Returns a HTLCStats about inbound pending htlcs + fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { + let context = self; + let mut stats = HTLCStats { + pending_htlcs: context.pending_inbound_htlcs.len() as u32, + pending_htlcs_value_msat: 0, + on_counterparty_tx_dust_exposure_msat: 0, + on_holder_tx_dust_exposure_msat: 0, + holding_cell_msat: 0, + on_holder_tx_holding_cell_htlcs_count: 0, + }; -/// This is for legacy reasons, present for forward-compatibility. -/// LDK versions older than 0.0.104 don't know how read/handle values other than default -/// from storage. Hence, we use this function to not persist default values of -/// `holder_selected_channel_reserve_satoshis` for channels into storage. -pub(crate) fn get_legacy_default_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)) -} + let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.opt_anchors() { + (0, 0) + } else { + let dust_buffer_feerate = context.get_dust_buffer_feerate(outbound_feerate_update) as u64; + (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) + }; + let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis; + let holder_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis; + for ref htlc in context.pending_inbound_htlcs.iter() { + stats.pending_htlcs_value_msat += htlc.amount_msat; + if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat { + stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat; + } + if htlc.amount_msat / 1000 < holder_dust_limit_success_sat { + stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat; + } + } + stats + } -// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. -// Note that num_htlcs should not include dust HTLCs. -#[inline] -fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { - feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 -} + /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell. + fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { + let context = self; + let mut stats = HTLCStats { + pending_htlcs: context.pending_outbound_htlcs.len() as u32, + pending_htlcs_value_msat: 0, + on_counterparty_tx_dust_exposure_msat: 0, + on_holder_tx_dust_exposure_msat: 0, + holding_cell_msat: 0, + on_holder_tx_holding_cell_htlcs_count: 0, + }; -// 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 -// inbound channel. -// -// Holder designates channel data owned for the benefit of the user client. -// Counterparty designates channel data owned by the another channel participant entity. -pub(super) struct Channel { - pub context: ChannelContext, -} + let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if context.opt_anchors() { + (0, 0) + } else { + let dust_buffer_feerate = context.get_dust_buffer_feerate(outbound_feerate_update) as u64; + (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) + }; + let counterparty_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis; + let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.holder_dust_limit_satoshis; + for ref htlc in context.pending_outbound_htlcs.iter() { + stats.pending_htlcs_value_msat += htlc.amount_msat; + if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat { + stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat; + } + if htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat { + stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat; + } + } -#[cfg(any(test, fuzzing))] -struct CommitmentTxInfoCached { - fee: u64, - total_pending_htlcs: usize, - next_holder_htlc_id: u64, - next_counterparty_htlc_id: u64, - feerate: u32, -} + for update in context.holding_cell_htlc_updates.iter() { + if let &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } = update { + stats.pending_htlcs += 1; + stats.pending_htlcs_value_msat += amount_msat; + stats.holding_cell_msat += amount_msat; + if *amount_msat / 1000 < counterparty_dust_limit_success_sat { + stats.on_counterparty_tx_dust_exposure_msat += amount_msat; + } + if *amount_msat / 1000 < holder_dust_limit_timeout_sat { + stats.on_holder_tx_dust_exposure_msat += amount_msat; + } else { + stats.on_holder_tx_holding_cell_htlcs_count += 1; + } + } + } + stats + } -pub const DEFAULT_MAX_HTLCS: u16 = 50; + /// Get the available balances, see [`AvailableBalances`]'s fields for more info. + /// 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. + pub fn get_available_balances(&self) -> AvailableBalances { + let context = &self; + // Note that we have to handle overflow due to the above case. + let inbound_stats = context.get_inbound_pending_htlc_stats(None); + let outbound_stats = context.get_outbound_pending_htlc_stats(None); -pub(crate) fn commitment_tx_base_weight(opt_anchors: bool) -> u64 { - const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; - const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124; - if opt_anchors { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } -} + let mut balance_msat = context.value_to_self_msat; + for ref htlc in context.pending_inbound_htlcs.iter() { + if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state { + balance_msat += htlc.amount_msat; + } + } + balance_msat -= outbound_stats.pending_htlcs_value_msat; -#[cfg(not(test))] -const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; -#[cfg(test)] -pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; + let outbound_capacity_msat = context.value_to_self_msat + .saturating_sub(outbound_stats.pending_htlcs_value_msat) + .saturating_sub( + context.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) * 1000); -pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330; + let mut available_capacity_msat = outbound_capacity_msat; -/// The percentage of the channel value `holder_max_htlc_value_in_flight_msat` used to be set to, -/// before this was made configurable. The percentage was made configurable in LDK 0.0.107, -/// although LDK 0.0.104+ enabled serialization of channels with a different value set for -/// `holder_max_htlc_value_in_flight_msat`. -pub const MAX_IN_FLIGHT_PERCENT_LEGACY: u8 = 10; + if context.is_outbound() { + // We should mind channel commit tx fee when computing how much of the available capacity + // can be used in the next htlc. Mirrors the logic in send_htlc. + // + // The fee depends on whether the amount we will be sending is above dust or not, + // and the answer will in turn change the amount itself — making it a circular + // dependency. + // This complicates the computation around dust-values, up to the one-htlc-value. + let mut real_dust_limit_timeout_sat = context.holder_dust_limit_satoshis; + if !context.opt_anchors() { + real_dust_limit_timeout_sat += context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000; + } -/// Maximum `funding_satoshis` value according to the BOLT #2 specification, if -/// `option_support_large_channel` (aka wumbo channels) is not supported. -/// It's 2^24 - 1. -pub const MAX_FUNDING_SATOSHIS_NO_WUMBO: u64 = (1 << 24) - 1; + let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered); + let max_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_above_dust, Some(())); + let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered); + let min_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * context.next_local_commit_tx_fee_msat(htlc_dust, Some(())); -/// Total bitcoin supply in satoshis. -pub const TOTAL_BITCOIN_SUPPLY_SATOSHIS: u64 = 21_000_000 * 1_0000_0000; + // We will first subtract the fee as if we were above-dust. Then, if the resulting + // value ends up being below dust, we have this fee available again. In that case, + // match the value to right-below-dust. + let mut capacity_minus_commitment_fee_msat: i64 = (available_capacity_msat as i64) - (max_reserved_commit_tx_fee_msat as i64); + if capacity_minus_commitment_fee_msat < (real_dust_limit_timeout_sat as i64) * 1000 { + let one_htlc_difference_msat = max_reserved_commit_tx_fee_msat - min_reserved_commit_tx_fee_msat; + debug_assert!(one_htlc_difference_msat != 0); + capacity_minus_commitment_fee_msat += one_htlc_difference_msat as i64; + capacity_minus_commitment_fee_msat = cmp::min(real_dust_limit_timeout_sat as i64 * 1000 - 1, capacity_minus_commitment_fee_msat); + available_capacity_msat = cmp::max(0, cmp::min(capacity_minus_commitment_fee_msat, available_capacity_msat as i64)) as u64; + } else { + available_capacity_msat = capacity_minus_commitment_fee_msat as u64; + } + } else { + // If the channel is inbound (i.e. counterparty pays the fee), we need to make sure + // sending a new HTLC won't reduce their balance below our reserve threshold. + let mut real_dust_limit_success_sat = context.counterparty_dust_limit_satoshis; + if !context.opt_anchors() { + real_dust_limit_success_sat += context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000; + } -/// The maximum network dust limit for standard script formats. This currently represents the -/// minimum output value for a P2SH output before Bitcoin Core 22 considers the entire -/// transaction non-standard and thus refuses to relay it. -/// We also use this as the maximum counterparty `dust_limit_satoshis` allowed, given many -/// implementations use this value for their dust limit today. -pub const MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS: u64 = 546; + let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered); + let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(htlc_above_dust, None); -/// The maximum channel dust limit we will accept from our counterparty. -pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS; + let holder_selected_chan_reserve_msat = context.holder_selected_channel_reserve_satoshis * 1000; + let remote_balance_msat = (context.channel_value_satoshis * 1000 - context.value_to_self_msat) + .saturating_sub(inbound_stats.pending_htlcs_value_msat); -/// The dust limit is used for both the commitment transaction outputs as well as the closing -/// transactions. For cooperative closing transactions, we require segwit outputs, though accept -/// *any* segwit scripts, which are allowed to be up to 42 bytes in length. -/// In order to avoid having to concern ourselves with standardness during the closing process, we -/// simply require our counterparty to use a dust limit which will leave any segwit output -/// standard. -/// See for more details. -pub const MIN_CHAN_DUST_LIMIT_SATOSHIS: u64 = 354; + if remote_balance_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat { + // If another HTLC's fee would reduce the remote's balance below the reserve limit + // we've selected for them, we can only send dust HTLCs. + available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1); + } + } -// Just a reasonable implementation-specific safe lower bound, higher than the dust limit. -pub const MIN_THEIR_CHAN_RESERVE_SATOSHIS: u64 = 1000; + let mut next_outbound_htlc_minimum_msat = context.counterparty_htlc_minimum_msat; -/// Used to return a simple Error back to ChannelManager. Will get converted to a -/// msgs::ErrorAction::SendErrorMessage or msgs::ErrorAction::IgnoreError as appropriate with our -/// channel_id in ChannelManager. -pub(super) enum ChannelError { - Ignore(String), - Warn(String), - Close(String), -} + // If we get close to our maximum dust exposure, we end up in a situation where we can send + // between zero and the remaining dust exposure limit remaining OR above the dust limit. + // Because we cannot express this as a simple min/max, we prefer to tell the user they can + // send above the dust limit (as the router can always overpay to meet the dust limit). + let mut remaining_msat_below_dust_exposure_limit = None; + let mut dust_exposure_dust_limit_msat = 0; -impl fmt::Debug for ChannelError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ChannelError::Ignore(ref e) => write!(f, "Ignore : {}", e), - &ChannelError::Warn(ref e) => write!(f, "Warn : {}", e), - &ChannelError::Close(ref e) => write!(f, "Close : {}", e), + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() { + (context.counterparty_dust_limit_satoshis, context.holder_dust_limit_satoshis) + } else { + let dust_buffer_feerate = context.get_dust_buffer_feerate(None) as u64; + (context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000, + context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000) + }; + let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat; + if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 { + remaining_msat_below_dust_exposure_limit = + Some(context.get_max_dust_htlc_exposure_msat().saturating_sub(on_counterparty_dust_htlc_exposure_msat)); + dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000); } - } -} -macro_rules! secp_check { - ($res: expr, $err: expr) => { - match $res { - Ok(thing) => thing, - Err(_) => return Err(ChannelError::Close($err)), + let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat; + if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > context.get_max_dust_htlc_exposure_msat() as i64 { + remaining_msat_below_dust_exposure_limit = Some(cmp::min( + remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()), + context.get_max_dust_htlc_exposure_msat().saturating_sub(on_holder_dust_htlc_exposure_msat))); + dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_timeout_dust_limit * 1000); } - }; -} -impl Channel { - fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures { - // The default channel type (ie the first one we try) depends on whether the channel is - // public - if it is, we just go with `only_static_remotekey` as it's the only option - // available. If it's private, we first try `scid_privacy` as it provides better privacy - // with no other changes, and fall back to `only_static_remotekey`. - let mut ret = ChannelTypeFeatures::only_static_remote_key(); - if !config.channel_handshake_config.announced_channel && - config.channel_handshake_config.negotiate_scid_privacy && - their_features.supports_scid_privacy() { - ret.set_scid_privacy_required(); - } - - // Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we - // set it now. If they don't understand it, we'll fall back to our default of - // `only_static_remotekey`. - #[cfg(anchors)] - { // Attributes are not allowed on if expressions on our current MSRV of 1.41. - if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx && - their_features.supports_anchors_zero_fee_htlc_tx() { - ret.set_anchors_zero_fee_htlc_tx_required(); + if let Some(remaining_limit_msat) = remaining_msat_below_dust_exposure_limit { + if available_capacity_msat < dust_exposure_dust_limit_msat { + available_capacity_msat = cmp::min(available_capacity_msat, remaining_limit_msat); + } else { + next_outbound_htlc_minimum_msat = cmp::max(next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat); } } - ret - } + available_capacity_msat = cmp::min(available_capacity_msat, + context.counterparty_max_htlc_value_in_flight_msat - outbound_stats.pending_htlcs_value_msat); - /// If we receive an error message, it may only be a rejection of the channel type we tried, - /// not of our ability to open any channel at all. Thus, on error, we should first call this - /// and see if we get a new `OpenChannel` message, otherwise the channel is failed. - pub(crate) fn maybe_handle_error_without_close(&mut self, chain_hash: BlockHash) -> Result { - if !self.context.is_outbound() || self.context.channel_state != ChannelState::OurInitSent as u32 { return Err(()); } - if self.context.channel_type == ChannelTypeFeatures::only_static_remote_key() { - // We've exhausted our options - return Err(()); + if outbound_stats.pending_htlcs + 1 > context.counterparty_max_accepted_htlcs as u32 { + available_capacity_msat = 0; } - // We support opening a few different types of channels. Try removing our additional - // features one by one until we've either arrived at our default or the counterparty has - // accepted one. - // - // Due to the order below, we may not negotiate `option_anchors_zero_fee_htlc_tx` if the - // counterparty doesn't support `option_scid_privacy`. Since `get_initial_channel_type` - // checks whether the counterparty supports every feature, this would only happen if the - // counterparty is advertising the feature, but rejecting channels proposing the feature for - // whatever reason. - if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { - self.context.channel_type.clear_anchors_zero_fee_htlc_tx(); - assert!(self.context.channel_transaction_parameters.opt_non_zero_fee_anchors.is_none()); - self.context.channel_transaction_parameters.opt_anchors = None; - } else if self.context.channel_type.supports_scid_privacy() { - self.context.channel_type.clear_scid_privacy(); - } else { - self.context.channel_type = ChannelTypeFeatures::only_static_remote_key(); + + AvailableBalances { + inbound_capacity_msat: cmp::max(context.channel_value_satoshis as i64 * 1000 + - context.value_to_self_msat as i64 + - context.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 + - context.holder_selected_channel_reserve_satoshis as i64 * 1000, + 0) as u64, + outbound_capacity_msat, + next_outbound_htlc_limit_msat: available_capacity_msat, + next_outbound_htlc_minimum_msat, + balance_msat, } - Ok(self.get_open_channel(chain_hash)) } - // Constructors: - pub fn new_outbound( - fee_estimator: &LowerBoundedFeeEstimator, entropy_source: &ES, signer_provider: &SP, counterparty_node_id: PublicKey, their_features: &InitFeatures, - channel_value_satoshis: u64, push_msat: u64, user_id: u128, config: &UserConfig, current_chain_height: u32, - outbound_scid_alias: u64 - ) -> Result, APIError> - where ES::Target: EntropySource, - SP::Target: SignerProvider, - F::Target: FeeEstimator, - { - let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay; - let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id); - let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); - let pubkeys = holder_signer.pubkeys().clone(); + pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option) { + let context = &self; + (context.holder_selected_channel_reserve_satoshis, context.counterparty_selected_channel_reserve_satoshis) + } - if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO { - return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)}); + /// 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. + /// + /// Optionally includes the `HTLCCandidate` given by `htlc` and an additional non-dust HTLC if + /// `fee_spike_buffer_htlc` is `Some`. + /// + /// The first extra HTLC is useful for determining whether we can accept a further HTLC, the + /// second allows for creating a buffer to ensure a further HTLC can always be accepted/added. + /// + /// Dust HTLCs are excluded. + fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { + let context = &self; + assert!(context.is_outbound()); + + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() { + (0, 0) + } else { + (context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, + context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) + }; + let real_dust_limit_success_sat = htlc_success_dust_limit + context.holder_dust_limit_satoshis; + let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.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; + } + } } - if channel_value_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS { - return Err(APIError::APIMisuseError{err: format!("funding_value must be smaller than the total bitcoin supply, it was {}", channel_value_satoshis)}); + + let mut included_htlcs = 0; + for ref htlc in context.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; } - let channel_value_msat = channel_value_satoshis * 1000; - if push_msat > channel_value_msat { - return Err(APIError::APIMisuseError { err: format!("Push value ({}) was larger than channel_value ({})", push_msat, channel_value_msat) }); + + for ref htlc in context.pending_outbound_htlcs.iter() { + if htlc.amount_msat / 1000 < real_dust_limit_timeout_sat { + continue + } + match htlc.state { + 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. + _ => {}, + } } - if holder_selected_contest_delay < BREAKDOWN_TIMEOUT { - return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)}); + + for htlc in context.holding_cell_htlc_updates.iter() { + match htlc { + &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. + } } - let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config); - if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { - // Protocol level safety check in place, although it should never happen because - // of `MIN_THEIR_CHAN_RESERVE_SATOSHIS` - return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) }); + + let num_htlcs = included_htlcs + addl_htlcs; + let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, context.opt_anchors()); + #[cfg(any(test, fuzzing))] + { + let mut fee = res; + if fee_spike_buffer_htlc.is_some() { + fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, context.opt_anchors()); + } + let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len() + + context.holding_cell_htlc_updates.len(); + let commitment_tx_info = CommitmentTxInfoCached { + fee, + total_pending_htlcs, + next_holder_htlc_id: match htlc.origin { + HTLCInitiator::LocalOffered => context.next_holder_htlc_id + 1, + HTLCInitiator::RemoteOffered => context.next_holder_htlc_id, + }, + next_counterparty_htlc_id: match htlc.origin { + HTLCInitiator::LocalOffered => context.next_counterparty_htlc_id, + HTLCInitiator::RemoteOffered => context.next_counterparty_htlc_id + 1, + }, + feerate: context.feerate_per_kw, + }; + *context.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); } + res + } - let channel_type = Self::get_initial_channel_type(&config, their_features); - debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config))); + /// 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 + /// + /// Optionally includes the `HTLCCandidate` given by `htlc` and an additional non-dust HTLC if + /// `fee_spike_buffer_htlc` is `Some`. + /// + /// The first extra HTLC is useful for determining whether we can accept a further HTLC, the + /// second allows for creating a buffer to ensure a further HTLC can always be accepted/added. + /// + /// Dust HTLCs are excluded. + fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { + let context = &self; + assert!(!context.is_outbound()); - let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.opt_anchors() { + (0, 0) + } else { + (context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, + context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) + }; + let real_dust_limit_success_sat = htlc_success_dust_limit + context.counterparty_dust_limit_satoshis; + let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + context.counterparty_dust_limit_satoshis; - let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, channel_type.requires_anchors_zero_fee_htlc_tx()); - if value_to_self_msat < commitment_tx_fee { - return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) }); + 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; + } + } } - let mut secp_ctx = Secp256k1::new(); - secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); - - let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { - match signer_provider.get_shutdown_scriptpubkey() { - Ok(scriptpubkey) => Some(scriptpubkey), - Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get shutdown scriptpubkey".to_owned()}), + // 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 context.pending_inbound_htlcs.iter() { + if htlc.amount_msat / 1000 <= real_dust_limit_timeout_sat { + continue } - } else { None }; + included_htlcs += 1; + } - if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey { - if !shutdown_scriptpubkey.is_compatible(&their_features) { - return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() }); + for ref htlc in context.pending_outbound_htlcs.iter() { + 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. + match htlc.state { + OutboundHTLCState::Committed => included_htlcs += 1, + OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1, + OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1, + _ => {}, } } - let destination_script = match signer_provider.get_destination_script() { - Ok(script) => script, - Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}), - }; + let num_htlcs = included_htlcs + addl_htlcs; + let res = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs, context.opt_anchors()); + #[cfg(any(test, fuzzing))] + { + let mut fee = res; + if fee_spike_buffer_htlc.is_some() { + fee = commit_tx_fee_msat(context.feerate_per_kw, num_htlcs - 1, context.opt_anchors()); + } + let total_pending_htlcs = context.pending_inbound_htlcs.len() + context.pending_outbound_htlcs.len(); + let commitment_tx_info = CommitmentTxInfoCached { + fee, + total_pending_htlcs, + next_holder_htlc_id: match htlc.origin { + HTLCInitiator::LocalOffered => context.next_holder_htlc_id + 1, + HTLCInitiator::RemoteOffered => context.next_holder_htlc_id, + }, + next_counterparty_htlc_id: match htlc.origin { + HTLCInitiator::LocalOffered => context.next_counterparty_htlc_id, + HTLCInitiator::RemoteOffered => context.next_counterparty_htlc_id + 1, + }, + feerate: context.feerate_per_kw, + }; + *context.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); + } + res + } +} - let temporary_channel_id = entropy_source.get_secure_random_bytes(); +// Internal utility functions for channels - Ok(Channel { - context: ChannelContext { - user_id, - - config: LegacyChannelConfig { - options: config.channel_config.clone(), - announced_channel: config.channel_handshake_config.announced_channel, - commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey, - }, - - prev_config: None, - - inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()), - - channel_id: temporary_channel_id, - temporary_channel_id: Some(temporary_channel_id), - channel_state: ChannelState::OurInitSent as u32, - announcement_sigs_state: AnnouncementSigsState::NotSent, - secp_ctx, - channel_value_satoshis, - - latest_monitor_update_id: 0, - - holder_signer, - shutdown_scriptpubkey, - destination_script, - - cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, - cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, - value_to_self_msat, +/// Returns the value to use for `holder_max_htlc_value_in_flight_msat` as a percentage of the +/// `channel_value_satoshis` in msat, set through +/// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`] +/// +/// The effective percentage is lower bounded by 1% and upper bounded by 100%. +/// +/// [`ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel`]: crate::util::config::ChannelHandshakeConfig::max_inbound_htlc_value_in_flight_percent_of_channel +fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64, config: &ChannelHandshakeConfig) -> u64 { + let configured_percent = if config.max_inbound_htlc_value_in_flight_percent_of_channel < 1 { + 1 + } else if config.max_inbound_htlc_value_in_flight_percent_of_channel > 100 { + 100 + } else { + config.max_inbound_htlc_value_in_flight_percent_of_channel as u64 + }; + channel_value_satoshis * 10 * configured_percent +} - pending_inbound_htlcs: Vec::new(), - pending_outbound_htlcs: Vec::new(), - holding_cell_htlc_updates: Vec::new(), - pending_update_fee: None, - holding_cell_update_fee: None, - next_holder_htlc_id: 0, - next_counterparty_htlc_id: 0, - update_time_counter: 1, +/// Returns a minimum channel reserve value the remote needs to maintain, +/// required by us according to the configured or default +/// [`ChannelHandshakeConfig::their_channel_reserve_proportional_millionths`] +/// +/// Guaranteed to return a value no larger than channel_value_satoshis +/// +/// This is used both for outbound and inbound channels and has lower bound +/// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`. +pub(crate) fn get_holder_selected_channel_reserve_satoshis(channel_value_satoshis: u64, config: &UserConfig) -> u64 { + let calculated_reserve = channel_value_satoshis.saturating_mul(config.channel_handshake_config.their_channel_reserve_proportional_millionths as u64) / 1_000_000; + cmp::min(channel_value_satoshis, cmp::max(calculated_reserve, MIN_THEIR_CHAN_RESERVE_SATOSHIS)) +} - resend_order: RAACommitmentOrder::CommitmentFirst, +/// This is for legacy reasons, present for forward-compatibility. +/// LDK versions older than 0.0.104 don't know how read/handle values other than default +/// from storage. Hence, we use this function to not persist default values of +/// `holder_selected_channel_reserve_satoshis` for channels into storage. +pub(crate) fn get_legacy_default_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)) +} - monitor_pending_channel_ready: false, - monitor_pending_revoke_and_ack: false, - monitor_pending_commitment_signed: false, - monitor_pending_forwards: Vec::new(), - monitor_pending_failures: Vec::new(), - monitor_pending_finalized_fulfills: Vec::new(), +// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. +// Note that num_htlcs should not include dust HTLCs. +#[inline] +fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { + feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 +} - #[cfg(debug_assertions)] - holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)), - #[cfg(debug_assertions)] - counterparty_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)), +// Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs. +// Note that num_htlcs should not include dust HTLCs. +fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { + // Note that we need to divide before multiplying to round properly, + // since the lowest denomination of bitcoin on-chain is the satoshi. + (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 +} - last_sent_closing_fee: None, - pending_counterparty_closing_signed: None, - closing_fee_limits: None, - target_closing_feerate_sats_per_kw: None, +// 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 +// inbound channel. +// +// Holder designates channel data owned for the benefit of the user client. +// Counterparty designates channel data owned by the another channel participant entity. +pub(super) struct Channel { + pub context: ChannelContext, +} - inbound_awaiting_accept: false, +#[cfg(any(test, fuzzing))] +struct CommitmentTxInfoCached { + fee: u64, + total_pending_htlcs: usize, + next_holder_htlc_id: u64, + next_counterparty_htlc_id: u64, + feerate: u32, +} - funding_tx_confirmed_in: None, - funding_tx_confirmation_height: 0, - short_channel_id: None, - channel_creation_height: current_chain_height, +pub const DEFAULT_MAX_HTLCS: u16 = 50; - feerate_per_kw: feerate, - 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: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config), - 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.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat }, - counterparty_max_accepted_htlcs: 0, - holder_max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, MAX_HTLCS), - minimum_depth: None, // Filled in in accept_channel +pub(crate) fn commitment_tx_base_weight(opt_anchors: bool) -> u64 { + const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; + const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124; + if opt_anchors { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } +} - counterparty_forwarding_info: None, +#[cfg(not(test))] +const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; +#[cfg(test)] +pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; - channel_transaction_parameters: ChannelTransactionParameters { - holder_pubkeys: pubkeys, - holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, - is_outbound_from_holder: true, - counterparty_parameters: None, - funding_outpoint: None, - opt_anchors: if channel_type.requires_anchors_zero_fee_htlc_tx() { Some(()) } else { None }, - opt_non_zero_fee_anchors: None - }, - funding_transaction: None, +pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330; - counterparty_cur_commitment_point: None, - counterparty_prev_commitment_point: None, - counterparty_node_id, +/// The percentage of the channel value `holder_max_htlc_value_in_flight_msat` used to be set to, +/// before this was made configurable. The percentage was made configurable in LDK 0.0.107, +/// although LDK 0.0.104+ enabled serialization of channels with a different value set for +/// `holder_max_htlc_value_in_flight_msat`. +pub const MAX_IN_FLIGHT_PERCENT_LEGACY: u8 = 10; - counterparty_shutdown_scriptpubkey: None, +/// Maximum `funding_satoshis` value according to the BOLT #2 specification, if +/// `option_support_large_channel` (aka wumbo channels) is not supported. +/// It's 2^24 - 1. +pub const MAX_FUNDING_SATOSHIS_NO_WUMBO: u64 = (1 << 24) - 1; - commitment_secrets: CounterpartyCommitmentSecrets::new(), +/// Total bitcoin supply in satoshis. +pub const TOTAL_BITCOIN_SUPPLY_SATOSHIS: u64 = 21_000_000 * 1_0000_0000; - channel_update_status: ChannelUpdateStatus::Enabled, - closing_signed_in_flight: false, +/// The maximum network dust limit for standard script formats. This currently represents the +/// minimum output value for a P2SH output before Bitcoin Core 22 considers the entire +/// transaction non-standard and thus refuses to relay it. +/// We also use this as the maximum counterparty `dust_limit_satoshis` allowed, given many +/// implementations use this value for their dust limit today. +pub const MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS: u64 = 546; - announcement_sigs: None, +/// The maximum channel dust limit we will accept from our counterparty. +pub const MAX_CHAN_DUST_LIMIT_SATOSHIS: u64 = MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS; - #[cfg(any(test, fuzzing))] - next_local_commitment_tx_fee_info_cached: Mutex::new(None), - #[cfg(any(test, fuzzing))] - next_remote_commitment_tx_fee_info_cached: Mutex::new(None), +/// The dust limit is used for both the commitment transaction outputs as well as the closing +/// transactions. For cooperative closing transactions, we require segwit outputs, though accept +/// *any* segwit scripts, which are allowed to be up to 42 bytes in length. +/// In order to avoid having to concern ourselves with standardness during the closing process, we +/// simply require our counterparty to use a dust limit which will leave any segwit output +/// standard. +/// See for more details. +pub const MIN_CHAN_DUST_LIMIT_SATOSHIS: u64 = 354; - workaround_lnd_bug_4006: None, - sent_message_awaiting_response: None, +// Just a reasonable implementation-specific safe lower bound, higher than the dust limit. +pub const MIN_THEIR_CHAN_RESERVE_SATOSHIS: u64 = 1000; - latest_inbound_scid_alias: None, - outbound_scid_alias, +/// Used to return a simple Error back to ChannelManager. Will get converted to a +/// msgs::ErrorAction::SendErrorMessage or msgs::ErrorAction::IgnoreError as appropriate with our +/// channel_id in ChannelManager. +pub(super) enum ChannelError { + Ignore(String), + Warn(String), + Close(String), +} - channel_pending_event_emitted: false, - channel_ready_event_emitted: false, +impl fmt::Debug for ChannelError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ChannelError::Ignore(ref e) => write!(f, "Ignore : {}", e), + &ChannelError::Warn(ref e) => write!(f, "Warn : {}", e), + &ChannelError::Close(ref e) => write!(f, "Close : {}", e), + } + } +} - #[cfg(any(test, fuzzing))] - historical_inbound_htlc_fulfills: HashSet::new(), +macro_rules! secp_check { + ($res: expr, $err: expr) => { + match $res { + Ok(thing) => thing, + Err(_) => return Err(ChannelError::Close($err)), + } + }; +} - channel_type, - channel_keys_id, +impl Channel { + fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures { + // The default channel type (ie the first one we try) depends on whether the channel is + // public - if it is, we just go with `only_static_remotekey` as it's the only option + // available. If it's private, we first try `scid_privacy` as it provides better privacy + // with no other changes, and fall back to `only_static_remotekey`. + let mut ret = ChannelTypeFeatures::only_static_remote_key(); + if !config.channel_handshake_config.announced_channel && + config.channel_handshake_config.negotiate_scid_privacy && + their_features.supports_scid_privacy() { + ret.set_scid_privacy_required(); + } - pending_monitor_updates: Vec::new(), + // Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we + // set it now. If they don't understand it, we'll fall back to our default of + // `only_static_remotekey`. + #[cfg(anchors)] + { // Attributes are not allowed on if expressions on our current MSRV of 1.41. + if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx && + their_features.supports_anchors_zero_fee_htlc_tx() { + ret.set_anchors_zero_fee_htlc_tx_required(); } - }) + } + + ret } - fn check_remote_fee(fee_estimator: &LowerBoundedFeeEstimator, + /// If we receive an error message, it may only be a rejection of the channel type we tried, + /// not of our ability to open any channel at all. Thus, on error, we should first call this + /// and see if we get a new `OpenChannel` message, otherwise the channel is failed. + pub(crate) fn maybe_handle_error_without_close(&mut self, chain_hash: BlockHash) -> Result { + if !self.context.is_outbound() || self.context.channel_state != ChannelState::OurInitSent as u32 { return Err(()); } + if self.context.channel_type == ChannelTypeFeatures::only_static_remote_key() { + // We've exhausted our options + return Err(()); + } + // We support opening a few different types of channels. Try removing our additional + // features one by one until we've either arrived at our default or the counterparty has + // accepted one. + // + // Due to the order below, we may not negotiate `option_anchors_zero_fee_htlc_tx` if the + // counterparty doesn't support `option_scid_privacy`. Since `get_initial_channel_type` + // checks whether the counterparty supports every feature, this would only happen if the + // counterparty is advertising the feature, but rejecting channels proposing the feature for + // whatever reason. + if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { + self.context.channel_type.clear_anchors_zero_fee_htlc_tx(); + assert!(self.context.channel_transaction_parameters.opt_non_zero_fee_anchors.is_none()); + self.context.channel_transaction_parameters.opt_anchors = None; + } else if self.context.channel_type.supports_scid_privacy() { + self.context.channel_type.clear_scid_privacy(); + } else { + self.context.channel_type = ChannelTypeFeatures::only_static_remote_key(); + } + Ok(self.get_open_channel(chain_hash)) + } + + // Constructors: + pub fn new_outbound( + fee_estimator: &LowerBoundedFeeEstimator, entropy_source: &ES, signer_provider: &SP, counterparty_node_id: PublicKey, their_features: &InitFeatures, + channel_value_satoshis: u64, push_msat: u64, user_id: u128, config: &UserConfig, current_chain_height: u32, + outbound_scid_alias: u64 + ) -> Result, APIError> + where ES::Target: EntropySource, + SP::Target: SignerProvider, + F::Target: FeeEstimator, + { + let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay; + let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id); + let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); + let pubkeys = holder_signer.pubkeys().clone(); + + if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO { + return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)}); + } + if channel_value_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS { + return Err(APIError::APIMisuseError{err: format!("funding_value must be smaller than the total bitcoin supply, it was {}", channel_value_satoshis)}); + } + let channel_value_msat = channel_value_satoshis * 1000; + if push_msat > channel_value_msat { + return Err(APIError::APIMisuseError { err: format!("Push value ({}) was larger than channel_value ({})", push_msat, channel_value_msat) }); + } + if holder_selected_contest_delay < BREAKDOWN_TIMEOUT { + return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)}); + } + let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config); + if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { + // Protocol level safety check in place, although it should never happen because + // of `MIN_THEIR_CHAN_RESERVE_SATOSHIS` + return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) }); + } + + let channel_type = Self::get_initial_channel_type(&config, their_features); + debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config))); + + let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); + + let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; + let commitment_tx_fee = commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, channel_type.requires_anchors_zero_fee_htlc_tx()); + if value_to_self_msat < commitment_tx_fee { + return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) }); + } + + let mut secp_ctx = Secp256k1::new(); + secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); + + let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { + match signer_provider.get_shutdown_scriptpubkey() { + Ok(scriptpubkey) => Some(scriptpubkey), + Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get shutdown scriptpubkey".to_owned()}), + } + } else { None }; + + if let Some(shutdown_scriptpubkey) = &shutdown_scriptpubkey { + if !shutdown_scriptpubkey.is_compatible(&their_features) { + return Err(APIError::IncompatibleShutdownScript { script: shutdown_scriptpubkey.clone() }); + } + } + + let destination_script = match signer_provider.get_destination_script() { + Ok(script) => script, + Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}), + }; + + let temporary_channel_id = entropy_source.get_secure_random_bytes(); + + Ok(Channel { + context: ChannelContext { + user_id, + + config: LegacyChannelConfig { + options: config.channel_config.clone(), + announced_channel: config.channel_handshake_config.announced_channel, + commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey, + }, + + prev_config: None, + + inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()), + + channel_id: temporary_channel_id, + temporary_channel_id: Some(temporary_channel_id), + channel_state: ChannelState::OurInitSent as u32, + announcement_sigs_state: AnnouncementSigsState::NotSent, + secp_ctx, + channel_value_satoshis, + + latest_monitor_update_id: 0, + + holder_signer, + shutdown_scriptpubkey, + destination_script, + + cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, + cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, + value_to_self_msat, + + pending_inbound_htlcs: Vec::new(), + pending_outbound_htlcs: Vec::new(), + holding_cell_htlc_updates: Vec::new(), + pending_update_fee: None, + holding_cell_update_fee: None, + next_holder_htlc_id: 0, + next_counterparty_htlc_id: 0, + update_time_counter: 1, + + resend_order: RAACommitmentOrder::CommitmentFirst, + + monitor_pending_channel_ready: false, + monitor_pending_revoke_and_ack: false, + monitor_pending_commitment_signed: false, + monitor_pending_forwards: Vec::new(), + monitor_pending_failures: Vec::new(), + monitor_pending_finalized_fulfills: Vec::new(), + + #[cfg(debug_assertions)] + holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)), + #[cfg(debug_assertions)] + counterparty_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)), + + last_sent_closing_fee: None, + pending_counterparty_closing_signed: None, + closing_fee_limits: None, + target_closing_feerate_sats_per_kw: None, + + inbound_awaiting_accept: false, + + funding_tx_confirmed_in: None, + funding_tx_confirmation_height: 0, + short_channel_id: None, + channel_creation_height: current_chain_height, + + feerate_per_kw: feerate, + 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: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config), + 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.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat }, + counterparty_max_accepted_htlcs: 0, + holder_max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, MAX_HTLCS), + minimum_depth: None, // Filled in in accept_channel + + counterparty_forwarding_info: None, + + channel_transaction_parameters: ChannelTransactionParameters { + holder_pubkeys: pubkeys, + holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, + is_outbound_from_holder: true, + counterparty_parameters: None, + funding_outpoint: None, + opt_anchors: if channel_type.requires_anchors_zero_fee_htlc_tx() { Some(()) } else { None }, + opt_non_zero_fee_anchors: None + }, + funding_transaction: None, + + counterparty_cur_commitment_point: None, + counterparty_prev_commitment_point: None, + counterparty_node_id, + + counterparty_shutdown_scriptpubkey: None, + + commitment_secrets: CounterpartyCommitmentSecrets::new(), + + channel_update_status: ChannelUpdateStatus::Enabled, + closing_signed_in_flight: false, + + announcement_sigs: None, + + #[cfg(any(test, fuzzing))] + next_local_commitment_tx_fee_info_cached: Mutex::new(None), + #[cfg(any(test, fuzzing))] + next_remote_commitment_tx_fee_info_cached: Mutex::new(None), + + workaround_lnd_bug_4006: None, + sent_message_awaiting_response: None, + + latest_inbound_scid_alias: None, + outbound_scid_alias, + + channel_pending_event_emitted: false, + channel_ready_event_emitted: false, + + #[cfg(any(test, fuzzing))] + historical_inbound_htlc_fulfills: HashSet::new(), + + channel_type, + channel_keys_id, + + pending_monitor_updates: Vec::new(), + } + }) + } + + fn check_remote_fee(fee_estimator: &LowerBoundedFeeEstimator, feerate_per_kw: u32, cur_feerate_per_kw: Option, logger: &L) -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger, { @@ -1950,7 +2376,7 @@ impl Channel { // check if the funder's amount for the initial commitment tx is sufficient // for full fee payment plus a few HTLCs to ensure the channel will be useful. let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors) / 1000; + let commitment_tx_fee = commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors) / 1000; if funders_amount_msat / 1000 < commitment_tx_fee { return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee))); } @@ -2426,931 +2852,511 @@ impl Channel { /// however, fail more than once as we wait for an upstream failure to be irrevocably committed /// before we fail backwards. /// - /// If we do fail twice, we `debug_assert!(false)` and return `Ok(None)`. Thus, this will always - /// return `Ok(_)` if preconditions are met. In any case, `Err`s will only be - /// [`ChannelError::Ignore`]. - fn fail_htlc(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, mut force_holding_cell: bool, logger: &L) - -> Result, ChannelError> where L::Target: Logger { - if (self.context.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) { - panic!("Was asked to fail an HTLC when channel was not in an operational state"); - } - assert_eq!(self.context.channel_state & ChannelState::ShutdownComplete as u32, 0); - - // ChannelManager may generate duplicate claims/fails due to HTLC update events from - // on-chain ChannelsMonitors during block rescan. Ideally we'd figure out a way to drop - // these, but for now we just have to treat them as normal. - - let mut pending_idx = core::usize::MAX; - for (idx, htlc) in self.context.pending_inbound_htlcs.iter().enumerate() { - if htlc.htlc_id == htlc_id_arg { - match htlc.state { - InboundHTLCState::Committed => {}, - InboundHTLCState::LocalRemoved(ref reason) => { - if let &InboundHTLCRemovalReason::Fulfill(_) = reason { - } else { - debug_assert!(false, "Tried to fail an HTLC that was already failed"); - } - return Ok(None); - }, - _ => { - debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); - return Err(ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc.htlc_id))); - } - } - pending_idx = idx; - } - } - if pending_idx == core::usize::MAX { - #[cfg(any(test, fuzzing))] - // If we failed to find an HTLC to fail, make sure it was previously fulfilled and this - // is simply a duplicate fail, not previously failed and we failed-back too early. - debug_assert!(self.context.historical_inbound_htlc_fulfills.contains(&htlc_id_arg)); - return Ok(None); - } - - if (self.context.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 { - debug_assert!(force_holding_cell, "!force_holding_cell is only called when emptying the holding cell, so we shouldn't end up back in it!"); - force_holding_cell = true; - } - - // Now update local state: - if force_holding_cell { - for pending_update in self.context.holding_cell_htlc_updates.iter() { - match pending_update { - &HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => { - if htlc_id_arg == htlc_id { - #[cfg(any(test, fuzzing))] - debug_assert!(self.context.historical_inbound_htlc_fulfills.contains(&htlc_id_arg)); - return Ok(None); - } - }, - &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => { - if htlc_id_arg == htlc_id { - debug_assert!(false, "Tried to fail an HTLC that was already failed"); - return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID".to_owned())); - } - }, - _ => {} - } - } - log_trace!(logger, "Placing failure for HTLC ID {} in holding cell in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id())); - self.context.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::FailHTLC { - htlc_id: htlc_id_arg, - err_packet, - }); - return Ok(None); - } - - log_trace!(logger, "Failing HTLC ID {} back with a update_fail_htlc message in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id())); - { - let htlc = &mut self.context.pending_inbound_htlcs[pending_idx]; - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone())); - } - - Ok(Some(msgs::UpdateFailHTLC { - channel_id: self.context.channel_id(), - htlc_id: htlc_id_arg, - reason: err_packet - })) - } - - // Message handlers: - - pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel, default_limits: &ChannelHandshakeLimits, their_features: &InitFeatures) -> Result<(), ChannelError> { - let peer_limits = if let Some(ref limits) = self.context.inbound_handshake_limits_override { limits } else { default_limits }; - - // Check sanity of message fields: - if !self.context.is_outbound() { - return Err(ChannelError::Close("Got an accept_channel message from an inbound peer".to_owned())); - } - if self.context.channel_state != ChannelState::OurInitSent as u32 { - return Err(ChannelError::Close("Got an accept_channel message at a strange time".to_owned())); - } - if msg.dust_limit_satoshis > 21000000 * 100000000 { - return Err(ChannelError::Close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", msg.dust_limit_satoshis))); - } - if msg.channel_reserve_satoshis > self.context.channel_value_satoshis { - return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.context.channel_value_satoshis))); - } - if msg.dust_limit_satoshis > self.context.holder_selected_channel_reserve_satoshis { - return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.context.holder_selected_channel_reserve_satoshis))); - } - if msg.channel_reserve_satoshis > self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis { - return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})", - msg.channel_reserve_satoshis, self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis))); - } - let full_channel_value_msat = (self.context.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000; - if msg.htlc_minimum_msat >= full_channel_value_msat { - return Err(ChannelError::Close(format!("Minimum htlc value ({}) is full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat))); - } - let max_delay_acceptable = u16::min(peer_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT); - if msg.to_self_delay > max_delay_acceptable { - return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, msg.to_self_delay))); - } - if msg.max_accepted_htlcs < 1 { - return Err(ChannelError::Close("0 max_accepted_htlcs makes for a useless channel".to_owned())); - } - if msg.max_accepted_htlcs > MAX_HTLCS { - return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.max_accepted_htlcs, MAX_HTLCS))); - } - - // Now check against optional parameters as set by config... - if msg.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat { - return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat))); - } - if msg.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat { - return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat))); - } - if msg.channel_reserve_satoshis > peer_limits.max_channel_reserve_satoshis { - return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, peer_limits.max_channel_reserve_satoshis))); - } - if msg.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs { - return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs))); - } - if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { - return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS))); - } - if msg.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS { - return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS))); - } - if msg.minimum_depth > peer_limits.max_minimum_depth { - return Err(ChannelError::Close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, msg.minimum_depth))); - } - - if let Some(ty) = &msg.channel_type { - if *ty != self.context.channel_type { - return Err(ChannelError::Close("Channel Type in accept_channel didn't match the one sent in open_channel.".to_owned())); - } - } else if their_features.supports_channel_type() { - // Assume they've accepted the channel type as they said they understand it. - } else { - let channel_type = ChannelTypeFeatures::from_init(&their_features); - if channel_type != ChannelTypeFeatures::only_static_remote_key() { - return Err(ChannelError::Close("Only static_remote_key is supported for non-negotiated channel types".to_owned())); - } - self.context.channel_type = channel_type; - } - - let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { - match &msg.shutdown_scriptpubkey { - &Some(ref script) => { - // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything - if script.len() == 0 { - None - } else { - if !script::is_bolt2_compliant(&script, their_features) { - return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script))); - } - Some(script.clone()) - } - }, - // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel - &None => { - return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned())); - } - } - } else { None }; - - self.context.counterparty_dust_limit_satoshis = msg.dust_limit_satoshis; - self.context.counterparty_max_htlc_value_in_flight_msat = cmp::min(msg.max_htlc_value_in_flight_msat, self.context.channel_value_satoshis * 1000); - self.context.counterparty_selected_channel_reserve_satoshis = Some(msg.channel_reserve_satoshis); - self.context.counterparty_htlc_minimum_msat = msg.htlc_minimum_msat; - self.context.counterparty_max_accepted_htlcs = msg.max_accepted_htlcs; - - if peer_limits.trust_own_funding_0conf { - self.context.minimum_depth = Some(msg.minimum_depth); - } else { - self.context.minimum_depth = Some(cmp::max(1, msg.minimum_depth)); - } - - let counterparty_pubkeys = ChannelPublicKeys { - funding_pubkey: msg.funding_pubkey, - revocation_basepoint: msg.revocation_basepoint, - payment_point: msg.payment_point, - delayed_payment_basepoint: msg.delayed_payment_basepoint, - htlc_basepoint: msg.htlc_basepoint - }; - - self.context.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters { - selected_contest_delay: msg.to_self_delay, - pubkeys: counterparty_pubkeys, - }); - - self.context.counterparty_cur_commitment_point = Some(msg.first_per_commitment_point); - self.context.counterparty_shutdown_scriptpubkey = counterparty_shutdown_scriptpubkey; - - self.context.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32; - self.context.inbound_handshake_limits_override = None; // We're done enforcing limits on our peer's handshake now. - - Ok(()) - } - - fn funding_created_signature(&mut self, sig: &Signature, logger: &L) -> Result<(Txid, CommitmentTransaction, Signature), ChannelError> where L::Target: Logger { - let funding_script = self.context.get_funding_redeemscript(); - - let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number); - let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx; - { - let trusted_tx = initial_commitment_tx.trust(); - let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); - let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis); - // They sign the holder commitment transaction... - log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.", - log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()), - encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]), - encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id())); - secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned()); - } - - let counterparty_keys = self.context.build_remote_transaction_keys(); - let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; - - let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); - let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); - log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}", - log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); - - let counterparty_signature = self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx) - .map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0; - - // We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish. - Ok((counterparty_initial_bitcoin_tx.txid, initial_commitment_tx, counterparty_signature)) - } - - pub fn funding_created( - &mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L - ) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> - where - SP::Target: SignerProvider, - L::Target: Logger - { - if self.context.is_outbound() { - return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned())); - } - if self.context.channel_state != (ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32) { - // BOLT 2 says that if we disconnect before we send funding_signed we SHOULD NOT - // remember the channel, so it's safe to just send an error_message here and drop the - // channel. - return Err(ChannelError::Close("Received funding_created after we got the channel!".to_owned())); - } - if self.context.inbound_awaiting_accept { - return Err(ChannelError::Close("FundingCreated message received before the channel was accepted".to_owned())); - } - if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) || - self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || - self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { - panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); - } - - let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index }; - self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); - // This is an externally observable change before we finish all our checks. In particular - // funding_created_signature may fail. - self.context.holder_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); - - let (counterparty_initial_commitment_txid, initial_commitment_tx, signature) = match self.funding_created_signature(&msg.signature, logger) { - Ok(res) => res, - Err(ChannelError::Close(e)) => { - self.context.channel_transaction_parameters.funding_outpoint = None; - return Err(ChannelError::Close(e)); - }, - Err(e) => { - // The only error we know how to handle is ChannelError::Close, so we fall over here - // to make sure we don't continue with an inconsistent state. - panic!("unexpected error type from funding_created_signature {:?}", e); - } - }; - - let holder_commitment_tx = HolderCommitmentTransaction::new( - initial_commitment_tx, - msg.signature, - Vec::new(), - &self.context.get_holder_pubkeys().funding_pubkey, - self.context.counterparty_funding_pubkey() - ); - - self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new()) - .map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?; - - // Now that we're past error-generating stuff, update our local state: - - let funding_redeemscript = self.context.get_funding_redeemscript(); - let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); - let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound()); - let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id); - monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); - let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, - shutdown_script, self.context.get_holder_selected_contest_delay(), - &self.context.destination_script, (funding_txo, funding_txo_script.clone()), - &self.context.channel_transaction_parameters, - funding_redeemscript.clone(), self.context.channel_value_satoshis, - obscure_factor, - holder_commitment_tx, best_block, self.context.counterparty_node_id); - - channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), logger); - - self.context.channel_state = ChannelState::FundingSent as u32; - self.context.channel_id = funding_txo.to_channel_id(); - self.context.cur_counterparty_commitment_transaction_number -= 1; - self.context.cur_holder_commitment_transaction_number -= 1; - - log_info!(logger, "Generated funding_signed for peer for channel {}", log_bytes!(self.context.channel_id())); - - let need_channel_ready = self.check_get_channel_ready(0).is_some(); - self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); - - Ok((msgs::FundingSigned { - channel_id: self.context.channel_id, - signature, - #[cfg(taproot)] - partial_signature_with_nonce: None, - }, channel_monitor)) - } - - /// 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( - &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L - ) -> Result, ChannelError> - where - SP::Target: SignerProvider, - L::Target: Logger - { - if !self.context.is_outbound() { - return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned())); - } - if self.context.channel_state & !(ChannelState::MonitorUpdateInProgress as u32) != ChannelState::FundingCreated as u32 { - return Err(ChannelError::Close("Received funding_signed in strange state!".to_owned())); - } - if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) || - self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || - self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { - panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); - } - - let funding_script = self.context.get_funding_redeemscript(); - - let counterparty_keys = self.context.build_remote_transaction_keys(); - let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; - let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); - let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); - - log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}", - log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); - - let holder_signer = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number); - let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx; - { - let trusted_tx = initial_commitment_tx.trust(); - let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); - let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis); - // They sign our commitment transaction, allowing us to broadcast the tx if we wish. - if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey) { - return Err(ChannelError::Close("Invalid funding_signed signature from peer".to_owned())); - } - } - - let holder_commitment_tx = HolderCommitmentTransaction::new( - initial_commitment_tx, - msg.signature, - Vec::new(), - &self.context.get_holder_pubkeys().funding_pubkey, - self.context.counterparty_funding_pubkey() - ); - - self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new()) - .map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?; - - - let funding_redeemscript = self.context.get_funding_redeemscript(); - let funding_txo = self.context.get_funding_txo().unwrap(); - let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); - let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound()); - let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id); - monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); - let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, - shutdown_script, self.context.get_holder_selected_contest_delay(), - &self.context.destination_script, (funding_txo, funding_txo_script), - &self.context.channel_transaction_parameters, - funding_redeemscript.clone(), self.context.channel_value_satoshis, - obscure_factor, - holder_commitment_tx, best_block, self.context.counterparty_node_id); - - channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), logger); - - assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update! - self.context.channel_state = ChannelState::FundingSent as u32; - self.context.cur_holder_commitment_transaction_number -= 1; - self.context.cur_counterparty_commitment_transaction_number -= 1; - - log_info!(logger, "Received funding_signed from peer for channel {}", log_bytes!(self.context.channel_id())); - - let need_channel_ready = self.check_get_channel_ready(0).is_some(); - self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); - Ok(channel_monitor) - } - - /// Handles a channel_ready message from our peer. If we've already sent our channel_ready - /// and the channel is now usable (and public), this may generate an announcement_signatures to - /// reply with. - pub fn channel_ready( - &mut self, msg: &msgs::ChannelReady, node_signer: &NS, genesis_block_hash: BlockHash, - user_config: &UserConfig, best_block: &BestBlock, logger: &L - ) -> Result, ChannelError> - where - NS::Target: NodeSigner, - L::Target: Logger - { - if self.context.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { - self.context.workaround_lnd_bug_4006 = Some(msg.clone()); - return Err(ChannelError::Ignore("Peer sent channel_ready when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned())); + /// If we do fail twice, we `debug_assert!(false)` and return `Ok(None)`. Thus, this will always + /// return `Ok(_)` if preconditions are met. In any case, `Err`s will only be + /// [`ChannelError::Ignore`]. + fn fail_htlc(&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, mut force_holding_cell: bool, logger: &L) + -> Result, ChannelError> where L::Target: Logger { + if (self.context.channel_state & (ChannelState::ChannelReady as u32)) != (ChannelState::ChannelReady as u32) { + panic!("Was asked to fail an HTLC when channel was not in an operational state"); } + assert_eq!(self.context.channel_state & ChannelState::ShutdownComplete as u32, 0); - if let Some(scid_alias) = msg.short_channel_id_alias { - if Some(scid_alias) != self.context.short_channel_id { - // The scid alias provided can be used to route payments *from* our counterparty, - // i.e. can be used for inbound payments and provided in invoices, but is not used - // when routing outbound payments. - self.context.latest_inbound_scid_alias = Some(scid_alias); + // ChannelManager may generate duplicate claims/fails due to HTLC update events from + // on-chain ChannelsMonitors during block rescan. Ideally we'd figure out a way to drop + // these, but for now we just have to treat them as normal. + + let mut pending_idx = core::usize::MAX; + for (idx, htlc) in self.context.pending_inbound_htlcs.iter().enumerate() { + if htlc.htlc_id == htlc_id_arg { + match htlc.state { + InboundHTLCState::Committed => {}, + InboundHTLCState::LocalRemoved(ref reason) => { + if let &InboundHTLCRemovalReason::Fulfill(_) = reason { + } else { + debug_assert!(false, "Tried to fail an HTLC that was already failed"); + } + return Ok(None); + }, + _ => { + debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); + return Err(ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc.htlc_id))); + } + } + pending_idx = idx; } } + if pending_idx == core::usize::MAX { + #[cfg(any(test, fuzzing))] + // If we failed to find an HTLC to fail, make sure it was previously fulfilled and this + // is simply a duplicate fail, not previously failed and we failed-back too early. + debug_assert!(self.context.historical_inbound_htlc_fulfills.contains(&htlc_id_arg)); + return Ok(None); + } - let non_shutdown_state = self.context.channel_state & (!MULTI_STATE_FLAGS); + if (self.context.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::PeerDisconnected as u32 | ChannelState::MonitorUpdateInProgress as u32)) != 0 { + debug_assert!(force_holding_cell, "!force_holding_cell is only called when emptying the holding cell, so we shouldn't end up back in it!"); + force_holding_cell = true; + } - if non_shutdown_state == ChannelState::FundingSent as u32 { - self.context.channel_state |= ChannelState::TheirChannelReady as u32; - } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurChannelReady as u32) { - self.context.channel_state = ChannelState::ChannelReady as u32 | (self.context.channel_state & MULTI_STATE_FLAGS); - self.context.update_time_counter += 1; - } else if self.context.channel_state & (ChannelState::ChannelReady as u32) != 0 || - // If we reconnected before sending our `channel_ready` they may still resend theirs: - (self.context.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32) == - (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32)) - { - // They probably disconnected/reconnected and re-sent the channel_ready, which is - // required, or they're sending a fresh SCID alias. - let expected_point = - if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 { - // If they haven't ever sent an updated point, the point they send should match - // the current one. - self.context.counterparty_cur_commitment_point - } else if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 2 { - // If we've advanced the commitment number once, the second commitment point is - // at `counterparty_prev_commitment_point`, which is not yet revoked. - debug_assert!(self.context.counterparty_prev_commitment_point.is_some()); - self.context.counterparty_prev_commitment_point - } else { - // If they have sent updated points, channel_ready is always supposed to match - // their "first" point, which we re-derive here. - Some(PublicKey::from_secret_key(&self.context.secp_ctx, &SecretKey::from_slice( - &self.context.commitment_secrets.get_secret(INITIAL_COMMITMENT_NUMBER - 1).expect("We should have all prev secrets available") - ).expect("We already advanced, so previous secret keys should have been validated already"))) - }; - if expected_point != Some(msg.next_per_commitment_point) { - return Err(ChannelError::Close("Peer sent a reconnect channel_ready with a different point".to_owned())); + // Now update local state: + if force_holding_cell { + for pending_update in self.context.holding_cell_htlc_updates.iter() { + match pending_update { + &HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => { + if htlc_id_arg == htlc_id { + #[cfg(any(test, fuzzing))] + debug_assert!(self.context.historical_inbound_htlc_fulfills.contains(&htlc_id_arg)); + return Ok(None); + } + }, + &HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => { + if htlc_id_arg == htlc_id { + debug_assert!(false, "Tried to fail an HTLC that was already failed"); + return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID".to_owned())); + } + }, + _ => {} + } } + log_trace!(logger, "Placing failure for HTLC ID {} in holding cell in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id())); + self.context.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::FailHTLC { + htlc_id: htlc_id_arg, + err_packet, + }); return Ok(None); - } else { - return Err(ChannelError::Close("Peer sent a channel_ready at a strange time".to_owned())); } - self.context.counterparty_prev_commitment_point = self.context.counterparty_cur_commitment_point; - self.context.counterparty_cur_commitment_point = Some(msg.next_per_commitment_point); - - log_info!(logger, "Received channel_ready from peer for channel {}", log_bytes!(self.context.channel_id())); + log_trace!(logger, "Failing HTLC ID {} back with a update_fail_htlc message in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id())); + { + let htlc = &mut self.context.pending_inbound_htlcs[pending_idx]; + htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone())); + } - Ok(self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, best_block.height(), logger)) + Ok(Some(msgs::UpdateFailHTLC { + channel_id: self.context.channel_id(), + htlc_id: htlc_id_arg, + reason: err_packet + })) } - /// Returns transaction if there is pending funding transaction that is yet to broadcast - pub fn unbroadcasted_funding(&self) -> Option { - if self.context.channel_state & (ChannelState::FundingCreated as u32) != 0 { - self.context.funding_transaction.clone() - } else { - None - } - } + // Message handlers: - /// Returns a HTLCStats about inbound pending htlcs - fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { - let mut stats = HTLCStats { - pending_htlcs: self.context.pending_inbound_htlcs.len() as u32, - pending_htlcs_value_msat: 0, - on_counterparty_tx_dust_exposure_msat: 0, - on_holder_tx_dust_exposure_msat: 0, - holding_cell_msat: 0, - on_holder_tx_holding_cell_htlcs_count: 0, - }; + pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel, default_limits: &ChannelHandshakeLimits, their_features: &InitFeatures) -> Result<(), ChannelError> { + let peer_limits = if let Some(ref limits) = self.context.inbound_handshake_limits_override { limits } else { default_limits }; - let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.opt_anchors() { - (0, 0) - } else { - let dust_buffer_feerate = self.context.get_dust_buffer_feerate(outbound_feerate_update) as u64; - (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) - }; - let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.context.counterparty_dust_limit_satoshis; - let holder_dust_limit_success_sat = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis; - for ref htlc in self.context.pending_inbound_htlcs.iter() { - stats.pending_htlcs_value_msat += htlc.amount_msat; - if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat { - stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat; - } - if htlc.amount_msat / 1000 < holder_dust_limit_success_sat { - stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat; - } + // Check sanity of message fields: + if !self.context.is_outbound() { + return Err(ChannelError::Close("Got an accept_channel message from an inbound peer".to_owned())); + } + if self.context.channel_state != ChannelState::OurInitSent as u32 { + return Err(ChannelError::Close("Got an accept_channel message at a strange time".to_owned())); + } + if msg.dust_limit_satoshis > 21000000 * 100000000 { + return Err(ChannelError::Close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", msg.dust_limit_satoshis))); + } + if msg.channel_reserve_satoshis > self.context.channel_value_satoshis { + return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.context.channel_value_satoshis))); + } + if msg.dust_limit_satoshis > self.context.holder_selected_channel_reserve_satoshis { + return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.context.holder_selected_channel_reserve_satoshis))); + } + if msg.channel_reserve_satoshis > self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis { + return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})", + msg.channel_reserve_satoshis, self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis))); + } + let full_channel_value_msat = (self.context.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000; + if msg.htlc_minimum_msat >= full_channel_value_msat { + return Err(ChannelError::Close(format!("Minimum htlc value ({}) is full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat))); + } + let max_delay_acceptable = u16::min(peer_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT); + if msg.to_self_delay > max_delay_acceptable { + return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, msg.to_self_delay))); + } + if msg.max_accepted_htlcs < 1 { + return Err(ChannelError::Close("0 max_accepted_htlcs makes for a useless channel".to_owned())); + } + if msg.max_accepted_htlcs > MAX_HTLCS { + return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.max_accepted_htlcs, MAX_HTLCS))); } - stats - } - /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell. - fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { - let mut stats = HTLCStats { - pending_htlcs: self.context.pending_outbound_htlcs.len() as u32, - pending_htlcs_value_msat: 0, - on_counterparty_tx_dust_exposure_msat: 0, - on_holder_tx_dust_exposure_msat: 0, - holding_cell_msat: 0, - on_holder_tx_holding_cell_htlcs_count: 0, - }; + // Now check against optional parameters as set by config... + if msg.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat { + return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat))); + } + if msg.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat { + return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat))); + } + if msg.channel_reserve_satoshis > peer_limits.max_channel_reserve_satoshis { + return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, peer_limits.max_channel_reserve_satoshis))); + } + if msg.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs { + return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs))); + } + if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { + return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS))); + } + if msg.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS { + return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS))); + } + if msg.minimum_depth > peer_limits.max_minimum_depth { + return Err(ChannelError::Close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, msg.minimum_depth))); + } - let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.context.opt_anchors() { - (0, 0) - } else { - let dust_buffer_feerate = self.context.get_dust_buffer_feerate(outbound_feerate_update) as u64; - (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) - }; - let counterparty_dust_limit_success_sat = htlc_success_dust_limit + self.context.counterparty_dust_limit_satoshis; - let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.context.holder_dust_limit_satoshis; - for ref htlc in self.context.pending_outbound_htlcs.iter() { - stats.pending_htlcs_value_msat += htlc.amount_msat; - if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat { - stats.on_counterparty_tx_dust_exposure_msat += htlc.amount_msat; + if let Some(ty) = &msg.channel_type { + if *ty != self.context.channel_type { + return Err(ChannelError::Close("Channel Type in accept_channel didn't match the one sent in open_channel.".to_owned())); } - if htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat { - stats.on_holder_tx_dust_exposure_msat += htlc.amount_msat; + } else if their_features.supports_channel_type() { + // Assume they've accepted the channel type as they said they understand it. + } else { + let channel_type = ChannelTypeFeatures::from_init(&their_features); + if channel_type != ChannelTypeFeatures::only_static_remote_key() { + return Err(ChannelError::Close("Only static_remote_key is supported for non-negotiated channel types".to_owned())); } + self.context.channel_type = channel_type; } - for update in self.context.holding_cell_htlc_updates.iter() { - if let &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } = update { - stats.pending_htlcs += 1; - stats.pending_htlcs_value_msat += amount_msat; - stats.holding_cell_msat += amount_msat; - if *amount_msat / 1000 < counterparty_dust_limit_success_sat { - stats.on_counterparty_tx_dust_exposure_msat += amount_msat; - } - if *amount_msat / 1000 < holder_dust_limit_timeout_sat { - stats.on_holder_tx_dust_exposure_msat += amount_msat; - } else { - stats.on_holder_tx_holding_cell_htlcs_count += 1; + let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { + match &msg.shutdown_scriptpubkey { + &Some(ref script) => { + // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything + if script.len() == 0 { + None + } else { + if !script::is_bolt2_compliant(&script, their_features) { + return Err(ChannelError::Close(format!("Peer is signaling upfront_shutdown but has provided an unacceptable scriptpubkey format: {}", script))); + } + Some(script.clone()) + } + }, + // Peer is signaling upfront shutdown but don't opt-out with correct mechanism (a.k.a 0-length script). Peer looks buggy, we fail the channel + &None => { + return Err(ChannelError::Close("Peer is signaling upfront_shutdown but we don't get any script. Use 0-length script to opt-out".to_owned())); } } + } else { None }; + + self.context.counterparty_dust_limit_satoshis = msg.dust_limit_satoshis; + self.context.counterparty_max_htlc_value_in_flight_msat = cmp::min(msg.max_htlc_value_in_flight_msat, self.context.channel_value_satoshis * 1000); + self.context.counterparty_selected_channel_reserve_satoshis = Some(msg.channel_reserve_satoshis); + self.context.counterparty_htlc_minimum_msat = msg.htlc_minimum_msat; + self.context.counterparty_max_accepted_htlcs = msg.max_accepted_htlcs; + + if peer_limits.trust_own_funding_0conf { + self.context.minimum_depth = Some(msg.minimum_depth); + } else { + self.context.minimum_depth = Some(cmp::max(1, msg.minimum_depth)); } - stats + + let counterparty_pubkeys = ChannelPublicKeys { + funding_pubkey: msg.funding_pubkey, + revocation_basepoint: msg.revocation_basepoint, + payment_point: msg.payment_point, + delayed_payment_basepoint: msg.delayed_payment_basepoint, + htlc_basepoint: msg.htlc_basepoint + }; + + self.context.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters { + selected_contest_delay: msg.to_self_delay, + pubkeys: counterparty_pubkeys, + }); + + self.context.counterparty_cur_commitment_point = Some(msg.first_per_commitment_point); + self.context.counterparty_shutdown_scriptpubkey = counterparty_shutdown_scriptpubkey; + + self.context.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32; + self.context.inbound_handshake_limits_override = None; // We're done enforcing limits on our peer's handshake now. + + Ok(()) } - /// Get the available balances, see [`AvailableBalances`]'s fields for more info. - /// 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. - pub fn get_available_balances(&self) -> AvailableBalances { - // Note that we have to handle overflow due to the above case. - let inbound_stats = self.get_inbound_pending_htlc_stats(None); - let outbound_stats = self.get_outbound_pending_htlc_stats(None); + fn funding_created_signature(&mut self, sig: &Signature, logger: &L) -> Result<(Txid, CommitmentTransaction, Signature), ChannelError> where L::Target: Logger { + let funding_script = self.context.get_funding_redeemscript(); - let mut balance_msat = self.context.value_to_self_msat; - for ref htlc in self.context.pending_inbound_htlcs.iter() { - if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state { - balance_msat += htlc.amount_msat; - } + let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number); + let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, false, logger).tx; + { + let trusted_tx = initial_commitment_tx.trust(); + let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); + let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis); + // They sign the holder commitment transaction... + log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.", + log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()), + encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]), + encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id())); + secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned()); } - balance_msat -= outbound_stats.pending_htlcs_value_msat; - let outbound_capacity_msat = self.context.value_to_self_msat - .saturating_sub(outbound_stats.pending_htlcs_value_msat) - .saturating_sub( - self.context.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) * 1000); + let counterparty_keys = self.context.build_remote_transaction_keys(); + let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; - let mut available_capacity_msat = outbound_capacity_msat; + let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); + let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); + log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}", + log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); + let counterparty_signature = self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx) + .map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0; + + // We sign "counterparty" commitment transaction, allowing them to broadcast the tx if they wish. + Ok((counterparty_initial_bitcoin_tx.txid, initial_commitment_tx, counterparty_signature)) + } + + pub fn funding_created( + &mut self, msg: &msgs::FundingCreated, best_block: BestBlock, signer_provider: &SP, logger: &L + ) -> Result<(msgs::FundingSigned, ChannelMonitor), ChannelError> + where + SP::Target: SignerProvider, + L::Target: Logger + { if self.context.is_outbound() { - // We should mind channel commit tx fee when computing how much of the available capacity - // can be used in the next htlc. Mirrors the logic in send_htlc. - // - // The fee depends on whether the amount we will be sending is above dust or not, - // and the answer will in turn change the amount itself — making it a circular - // dependency. - // This complicates the computation around dust-values, up to the one-htlc-value. - let mut real_dust_limit_timeout_sat = self.context.holder_dust_limit_satoshis; - if !self.context.opt_anchors() { - real_dust_limit_timeout_sat += self.context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000; - } + return Err(ChannelError::Close("Received funding_created for an outbound channel?".to_owned())); + } + if self.context.channel_state != (ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32) { + // BOLT 2 says that if we disconnect before we send funding_signed we SHOULD NOT + // remember the channel, so it's safe to just send an error_message here and drop the + // channel. + return Err(ChannelError::Close("Received funding_created after we got the channel!".to_owned())); + } + if self.context.inbound_awaiting_accept { + return Err(ChannelError::Close("FundingCreated message received before the channel was accepted".to_owned())); + } + if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) || + self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || + self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { + panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); + } - let htlc_above_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000, HTLCInitiator::LocalOffered); - let max_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * self.next_local_commit_tx_fee_msat(htlc_above_dust, Some(())); - let htlc_dust = HTLCCandidate::new(real_dust_limit_timeout_sat * 1000 - 1, HTLCInitiator::LocalOffered); - let min_reserved_commit_tx_fee_msat = FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * self.next_local_commit_tx_fee_msat(htlc_dust, Some(())); + let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index }; + self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); + // This is an externally observable change before we finish all our checks. In particular + // funding_created_signature may fail. + self.context.holder_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); - // We will first subtract the fee as if we were above-dust. Then, if the resulting - // value ends up being below dust, we have this fee available again. In that case, - // match the value to right-below-dust. - let mut capacity_minus_commitment_fee_msat: i64 = (available_capacity_msat as i64) - (max_reserved_commit_tx_fee_msat as i64); - if capacity_minus_commitment_fee_msat < (real_dust_limit_timeout_sat as i64) * 1000 { - let one_htlc_difference_msat = max_reserved_commit_tx_fee_msat - min_reserved_commit_tx_fee_msat; - debug_assert!(one_htlc_difference_msat != 0); - capacity_minus_commitment_fee_msat += one_htlc_difference_msat as i64; - capacity_minus_commitment_fee_msat = cmp::min(real_dust_limit_timeout_sat as i64 * 1000 - 1, capacity_minus_commitment_fee_msat); - available_capacity_msat = cmp::max(0, cmp::min(capacity_minus_commitment_fee_msat, available_capacity_msat as i64)) as u64; - } else { - available_capacity_msat = capacity_minus_commitment_fee_msat as u64; - } - } else { - // If the channel is inbound (i.e. counterparty pays the fee), we need to make sure - // sending a new HTLC won't reduce their balance below our reserve threshold. - let mut real_dust_limit_success_sat = self.context.counterparty_dust_limit_satoshis; - if !self.context.opt_anchors() { - real_dust_limit_success_sat += self.context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000; + let (counterparty_initial_commitment_txid, initial_commitment_tx, signature) = match self.funding_created_signature(&msg.signature, logger) { + Ok(res) => res, + Err(ChannelError::Close(e)) => { + self.context.channel_transaction_parameters.funding_outpoint = None; + return Err(ChannelError::Close(e)); + }, + Err(e) => { + // The only error we know how to handle is ChannelError::Close, so we fall over here + // to make sure we don't continue with an inconsistent state. + panic!("unexpected error type from funding_created_signature {:?}", e); } + }; - let htlc_above_dust = HTLCCandidate::new(real_dust_limit_success_sat * 1000, HTLCInitiator::LocalOffered); - let max_reserved_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_above_dust, None); + let holder_commitment_tx = HolderCommitmentTransaction::new( + initial_commitment_tx, + msg.signature, + Vec::new(), + &self.context.get_holder_pubkeys().funding_pubkey, + self.context.counterparty_funding_pubkey() + ); - let holder_selected_chan_reserve_msat = self.context.holder_selected_channel_reserve_satoshis * 1000; - let remote_balance_msat = (self.context.channel_value_satoshis * 1000 - self.context.value_to_self_msat) - .saturating_sub(inbound_stats.pending_htlcs_value_msat); + self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new()) + .map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?; - if remote_balance_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat { - // If another HTLC's fee would reduce the remote's balance below the reserve limit - // we've selected for them, we can only send dust HTLCs. - available_capacity_msat = cmp::min(available_capacity_msat, real_dust_limit_success_sat * 1000 - 1); - } - } + // Now that we're past error-generating stuff, update our local state: - let mut next_outbound_htlc_minimum_msat = self.context.counterparty_htlc_minimum_msat; + let funding_redeemscript = self.context.get_funding_redeemscript(); + let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); + let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound()); + let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); + let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id); + monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); + let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, + shutdown_script, self.context.get_holder_selected_contest_delay(), + &self.context.destination_script, (funding_txo, funding_txo_script.clone()), + &self.context.channel_transaction_parameters, + funding_redeemscript.clone(), self.context.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, best_block, self.context.counterparty_node_id); - // If we get close to our maximum dust exposure, we end up in a situation where we can send - // between zero and the remaining dust exposure limit remaining OR above the dust limit. - // Because we cannot express this as a simple min/max, we prefer to tell the user they can - // send above the dust limit (as the router can always overpay to meet the dust limit). - let mut remaining_msat_below_dust_exposure_limit = None; - let mut dust_exposure_dust_limit_msat = 0; + channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), logger); - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.context.opt_anchors() { - (self.context.counterparty_dust_limit_satoshis, self.context.holder_dust_limit_satoshis) - } else { - let dust_buffer_feerate = self.context.get_dust_buffer_feerate(None) as u64; - (self.context.counterparty_dust_limit_satoshis + dust_buffer_feerate * htlc_success_tx_weight(false) / 1000, - self.context.holder_dust_limit_satoshis + dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000) - }; - let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat; - if on_counterparty_dust_htlc_exposure_msat as i64 + htlc_success_dust_limit as i64 * 1000 - 1 > self.context.get_max_dust_htlc_exposure_msat() as i64 { - remaining_msat_below_dust_exposure_limit = - Some(self.context.get_max_dust_htlc_exposure_msat().saturating_sub(on_counterparty_dust_htlc_exposure_msat)); - dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_success_dust_limit * 1000); - } + self.context.channel_state = ChannelState::FundingSent as u32; + self.context.channel_id = funding_txo.to_channel_id(); + self.context.cur_counterparty_commitment_transaction_number -= 1; + self.context.cur_holder_commitment_transaction_number -= 1; - let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat; - if on_holder_dust_htlc_exposure_msat as i64 + htlc_timeout_dust_limit as i64 * 1000 - 1 > self.context.get_max_dust_htlc_exposure_msat() as i64 { - remaining_msat_below_dust_exposure_limit = Some(cmp::min( - remaining_msat_below_dust_exposure_limit.unwrap_or(u64::max_value()), - self.context.get_max_dust_htlc_exposure_msat().saturating_sub(on_holder_dust_htlc_exposure_msat))); - dust_exposure_dust_limit_msat = cmp::max(dust_exposure_dust_limit_msat, htlc_timeout_dust_limit * 1000); + log_info!(logger, "Generated funding_signed for peer for channel {}", log_bytes!(self.context.channel_id())); + + let need_channel_ready = self.check_get_channel_ready(0).is_some(); + self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); + + Ok((msgs::FundingSigned { + channel_id: self.context.channel_id, + signature, + #[cfg(taproot)] + partial_signature_with_nonce: None, + }, channel_monitor)) + } + + /// 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( + &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L + ) -> Result, ChannelError> + where + SP::Target: SignerProvider, + L::Target: Logger + { + if !self.context.is_outbound() { + return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned())); + } + if self.context.channel_state & !(ChannelState::MonitorUpdateInProgress as u32) != ChannelState::FundingCreated as u32 { + return Err(ChannelError::Close("Received funding_signed in strange state!".to_owned())); + } + if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) || + self.context.cur_counterparty_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER || + self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER { + panic!("Should not have advanced channel commitment tx numbers prior to funding_created"); } - if let Some(remaining_limit_msat) = remaining_msat_below_dust_exposure_limit { - if available_capacity_msat < dust_exposure_dust_limit_msat { - available_capacity_msat = cmp::min(available_capacity_msat, remaining_limit_msat); - } else { - next_outbound_htlc_minimum_msat = cmp::max(next_outbound_htlc_minimum_msat, dust_exposure_dust_limit_msat); + let funding_script = self.context.get_funding_redeemscript(); + + let counterparty_keys = self.context.build_remote_transaction_keys(); + let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; + let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); + let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); + + log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}", + log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); + + let holder_signer = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number); + let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx; + { + let trusted_tx = initial_commitment_tx.trust(); + let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); + let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.context.channel_value_satoshis); + // They sign our commitment transaction, allowing us to broadcast the tx if we wish. + if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey) { + return Err(ChannelError::Close("Invalid funding_signed signature from peer".to_owned())); } } - available_capacity_msat = cmp::min(available_capacity_msat, - self.context.counterparty_max_htlc_value_in_flight_msat - outbound_stats.pending_htlcs_value_msat); + let holder_commitment_tx = HolderCommitmentTransaction::new( + initial_commitment_tx, + msg.signature, + Vec::new(), + &self.context.get_holder_pubkeys().funding_pubkey, + self.context.counterparty_funding_pubkey() + ); - if outbound_stats.pending_htlcs + 1 > self.context.counterparty_max_accepted_htlcs as u32 { - available_capacity_msat = 0; - } + self.context.holder_signer.validate_holder_commitment(&holder_commitment_tx, Vec::new()) + .map_err(|_| ChannelError::Close("Failed to validate our commitment".to_owned()))?; - AvailableBalances { - inbound_capacity_msat: cmp::max(self.context.channel_value_satoshis as i64 * 1000 - - self.context.value_to_self_msat as i64 - - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 - - self.context.holder_selected_channel_reserve_satoshis as i64 * 1000, - 0) as u64, - outbound_capacity_msat, - next_outbound_htlc_limit_msat: available_capacity_msat, - next_outbound_htlc_minimum_msat, - balance_msat, - } - } - pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option) { - (self.context.holder_selected_channel_reserve_satoshis, self.context.counterparty_selected_channel_reserve_satoshis) - } + let funding_redeemscript = self.context.get_funding_redeemscript(); + let funding_txo = self.context.get_funding_txo().unwrap(); + let funding_txo_script = funding_redeemscript.to_v0_p2wsh(); + let obscure_factor = get_commitment_transaction_number_obscure_factor(&self.context.get_holder_pubkeys().payment_point, &self.context.get_counterparty_pubkeys().payment_point, self.context.is_outbound()); + let shutdown_script = self.context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); + let mut monitor_signer = signer_provider.derive_channel_signer(self.context.channel_value_satoshis, self.context.channel_keys_id); + monitor_signer.provide_channel_parameters(&self.context.channel_transaction_parameters); + let channel_monitor = ChannelMonitor::new(self.context.secp_ctx.clone(), monitor_signer, + shutdown_script, self.context.get_holder_selected_contest_delay(), + &self.context.destination_script, (funding_txo, funding_txo_script), + &self.context.channel_transaction_parameters, + funding_redeemscript.clone(), self.context.channel_value_satoshis, + obscure_factor, + holder_commitment_tx, best_block, self.context.counterparty_node_id); - // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs. - // Note that num_htlcs should not include dust HTLCs. - fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { - // Note that we need to divide before multiplying to round properly, - // since the lowest denomination of bitcoin on-chain is the satoshi. - (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 - } + channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.context.cur_counterparty_commitment_transaction_number, self.context.counterparty_cur_commitment_point.unwrap(), logger); - /// 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. - /// - /// Optionally includes the `HTLCCandidate` given by `htlc` and an additional non-dust HTLC if - /// `fee_spike_buffer_htlc` is `Some`. - /// - /// The first extra HTLC is useful for determining whether we can accept a further HTLC, the - /// second allows for creating a buffer to ensure a further HTLC can always be accepted/added. - /// - /// Dust HTLCs are excluded. - fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { - assert!(self.context.is_outbound()); + assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update! + self.context.channel_state = ChannelState::FundingSent as u32; + self.context.cur_holder_commitment_transaction_number -= 1; + self.context.cur_counterparty_commitment_transaction_number -= 1; - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.context.opt_anchors() { - (0, 0) - } else { - (self.context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, - self.context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) - }; - let real_dust_limit_success_sat = htlc_success_dust_limit + self.context.holder_dust_limit_satoshis; - let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.context.holder_dust_limit_satoshis; + log_info!(logger, "Received funding_signed from peer for channel {}", log_bytes!(self.context.channel_id())); - 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 need_channel_ready = self.check_get_channel_ready(0).is_some(); + self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new()); + Ok(channel_monitor) + } - let mut included_htlcs = 0; - for ref htlc in self.context.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; + /// Handles a channel_ready message from our peer. If we've already sent our channel_ready + /// and the channel is now usable (and public), this may generate an announcement_signatures to + /// reply with. + pub fn channel_ready( + &mut self, msg: &msgs::ChannelReady, node_signer: &NS, genesis_block_hash: BlockHash, + user_config: &UserConfig, best_block: &BestBlock, logger: &L + ) -> Result, ChannelError> + where + NS::Target: NodeSigner, + L::Target: Logger + { + if self.context.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { + self.context.workaround_lnd_bug_4006 = Some(msg.clone()); + return Err(ChannelError::Ignore("Peer sent channel_ready when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned())); } - for ref htlc in self.context.pending_outbound_htlcs.iter() { - if htlc.amount_msat / 1000 < real_dust_limit_timeout_sat { - continue - } - match htlc.state { - 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. - _ => {}, + if let Some(scid_alias) = msg.short_channel_id_alias { + if Some(scid_alias) != self.context.short_channel_id { + // The scid alias provided can be used to route payments *from* our counterparty, + // i.e. can be used for inbound payments and provided in invoices, but is not used + // when routing outbound payments. + self.context.latest_inbound_scid_alias = Some(scid_alias); } } - for htlc in self.context.holding_cell_htlc_updates.iter() { - match htlc { - &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. - } - } + let non_shutdown_state = self.context.channel_state & (!MULTI_STATE_FLAGS); - let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.context.feerate_per_kw, num_htlcs, self.context.opt_anchors()); - #[cfg(any(test, fuzzing))] + if non_shutdown_state == ChannelState::FundingSent as u32 { + self.context.channel_state |= ChannelState::TheirChannelReady as u32; + } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurChannelReady as u32) { + self.context.channel_state = ChannelState::ChannelReady as u32 | (self.context.channel_state & MULTI_STATE_FLAGS); + self.context.update_time_counter += 1; + } else if self.context.channel_state & (ChannelState::ChannelReady as u32) != 0 || + // If we reconnected before sending our `channel_ready` they may still resend theirs: + (self.context.channel_state & (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32) == + (ChannelState::FundingSent as u32 | ChannelState::TheirChannelReady as u32)) { - let mut fee = res; - if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.context.feerate_per_kw, num_htlcs - 1, self.context.opt_anchors()); + // They probably disconnected/reconnected and re-sent the channel_ready, which is + // required, or they're sending a fresh SCID alias. + let expected_point = + if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 1 { + // If they haven't ever sent an updated point, the point they send should match + // the current one. + self.context.counterparty_cur_commitment_point + } else if self.context.cur_counterparty_commitment_transaction_number == INITIAL_COMMITMENT_NUMBER - 2 { + // If we've advanced the commitment number once, the second commitment point is + // at `counterparty_prev_commitment_point`, which is not yet revoked. + debug_assert!(self.context.counterparty_prev_commitment_point.is_some()); + self.context.counterparty_prev_commitment_point + } else { + // If they have sent updated points, channel_ready is always supposed to match + // their "first" point, which we re-derive here. + Some(PublicKey::from_secret_key(&self.context.secp_ctx, &SecretKey::from_slice( + &self.context.commitment_secrets.get_secret(INITIAL_COMMITMENT_NUMBER - 1).expect("We should have all prev secrets available") + ).expect("We already advanced, so previous secret keys should have been validated already"))) + }; + if expected_point != Some(msg.next_per_commitment_point) { + return Err(ChannelError::Close("Peer sent a reconnect channel_ready with a different point".to_owned())); } - let total_pending_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len() - + self.context.holding_cell_htlc_updates.len(); - let commitment_tx_info = CommitmentTxInfoCached { - fee, - total_pending_htlcs, - next_holder_htlc_id: match htlc.origin { - HTLCInitiator::LocalOffered => self.context.next_holder_htlc_id + 1, - HTLCInitiator::RemoteOffered => self.context.next_holder_htlc_id, - }, - next_counterparty_htlc_id: match htlc.origin { - HTLCInitiator::LocalOffered => self.context.next_counterparty_htlc_id, - HTLCInitiator::RemoteOffered => self.context.next_counterparty_htlc_id + 1, - }, - feerate: self.context.feerate_per_kw, - }; - *self.context.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 - /// - /// Optionally includes the `HTLCCandidate` given by `htlc` and an additional non-dust HTLC if - /// `fee_spike_buffer_htlc` is `Some`. - /// - /// The first extra HTLC is useful for determining whether we can accept a further HTLC, the - /// second allows for creating a buffer to ensure a further HTLC can always be accepted/added. - /// - /// Dust HTLCs are excluded. - fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { - assert!(!self.context.is_outbound()); - - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.context.opt_anchors() { - (0, 0) + return Ok(None); } else { - (self.context.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, - self.context.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) - }; - let real_dust_limit_success_sat = htlc_success_dust_limit + self.context.counterparty_dust_limit_satoshis; - let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.context.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; - } - } + return Err(ChannelError::Close("Peer sent a channel_ready at a strange time".to_owned())); } - // 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.context.pending_inbound_htlcs.iter() { - if htlc.amount_msat / 1000 <= real_dust_limit_timeout_sat { - continue - } - included_htlcs += 1; - } + self.context.counterparty_prev_commitment_point = self.context.counterparty_cur_commitment_point; + self.context.counterparty_cur_commitment_point = Some(msg.next_per_commitment_point); - for ref htlc in self.context.pending_outbound_htlcs.iter() { - 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. - match htlc.state { - OutboundHTLCState::Committed => included_htlcs += 1, - OutboundHTLCState::RemoteRemoved {..} => included_htlcs += 1, - OutboundHTLCState::LocalAnnounced { .. } => included_htlcs += 1, - _ => {}, - } - } + log_info!(logger, "Received channel_ready from peer for channel {}", log_bytes!(self.context.channel_id())); - let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.context.feerate_per_kw, num_htlcs, self.context.opt_anchors()); - #[cfg(any(test, fuzzing))] - { - let mut fee = res; - if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.context.feerate_per_kw, num_htlcs - 1, self.context.opt_anchors()); - } - let total_pending_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len(); - let commitment_tx_info = CommitmentTxInfoCached { - fee, - total_pending_htlcs, - next_holder_htlc_id: match htlc.origin { - HTLCInitiator::LocalOffered => self.context.next_holder_htlc_id + 1, - HTLCInitiator::RemoteOffered => self.context.next_holder_htlc_id, - }, - next_counterparty_htlc_id: match htlc.origin { - HTLCInitiator::LocalOffered => self.context.next_counterparty_htlc_id, - HTLCInitiator::RemoteOffered => self.context.next_counterparty_htlc_id + 1, - }, - feerate: self.context.feerate_per_kw, - }; - *self.context.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); + Ok(self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, best_block.height(), logger)) + } + + /// Returns transaction if there is pending funding transaction that is yet to broadcast + pub fn unbroadcasted_funding(&self) -> Option { + if self.context.channel_state & (ChannelState::FundingCreated as u32) != 0 { + self.context.funding_transaction.clone() + } else { + None } - res } pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, mut pending_forward_status: PendingHTLCStatus, create_pending_htlc_status: F, logger: &L) -> Result<(), ChannelError> @@ -3378,8 +3384,8 @@ impl Channel { return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.context.holder_htlc_minimum_msat, msg.amount_msat))); } - let inbound_stats = self.get_inbound_pending_htlc_stats(None); - let outbound_stats = self.get_outbound_pending_htlc_stats(None); + let inbound_stats = self.context.get_inbound_pending_htlc_stats(None); + let outbound_stats = self.context.get_outbound_pending_htlc_stats(None); if inbound_stats.pending_htlcs + 1 > self.context.holder_max_accepted_htlcs as u32 { return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", self.context.holder_max_accepted_htlcs))); } @@ -3446,7 +3452,7 @@ impl Channel { // feerate_per_kw, while maintaining their channel reserve (as required by the spec). let remote_commit_tx_fee_msat = if self.context.is_outbound() { 0 } else { 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 + self.context.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())); @@ -3466,7 +3472,7 @@ impl Channel { // 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(())); + let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.context.next_remote_commit_tx_fee_msat(htlc_candidate, Some(())); if pending_remote_value_msat - msg.amount_msat - self.context.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. @@ -3476,7 +3482,7 @@ impl Channel { } else { // Check that they won't violate our local required channel reserve by adding this HTLC. 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); + let local_commit_tx_fee_msat = self.context.next_local_commit_tx_fee_msat(htlc_candidate, None); if self.context.value_to_self_msat < self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 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())); } @@ -4177,8 +4183,8 @@ impl Channel { } // Before proposing a feerate update, check that we can actually afford the new fee. - let inbound_stats = self.get_inbound_pending_htlc_stats(Some(feerate_per_kw)); - let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw)); + let inbound_stats = self.context.get_inbound_pending_htlc_stats(Some(feerate_per_kw)); + let outbound_stats = self.context.get_outbound_pending_htlc_stats(Some(feerate_per_kw)); let keys = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number); let commitment_stats = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &keys, true, true, logger); let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.opt_anchors()) * 1000; @@ -4429,8 +4435,8 @@ impl Channel { // `get_dust_buffer_feerate` considers the `pending_update_fee` status), check that we // won't be pushed over our dust exposure limit by the feerate increase. if feerate_over_dust_buffer { - let inbound_stats = self.get_inbound_pending_htlc_stats(None); - let outbound_stats = self.get_outbound_pending_htlc_stats(None); + let inbound_stats = self.context.get_inbound_pending_htlc_stats(None); + let outbound_stats = self.context.get_outbound_pending_htlc_stats(None); let holder_tx_dust_exposure = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat; let counterparty_tx_dust_exposure = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat; if holder_tx_dust_exposure > self.context.get_max_dust_htlc_exposure_msat() { @@ -6042,7 +6048,7 @@ impl Channel { return Err(ChannelError::Ignore("Cannot send 0-msat HTLC".to_owned())); } - let available_balances = self.get_available_balances(); + let available_balances = self.context.get_available_balances(); if amount_msat < available_balances.next_outbound_htlc_minimum_msat { return Err(ChannelError::Ignore(format!("Cannot send less than our next-HTLC minimum - {} msat", available_balances.next_outbound_htlc_minimum_msat))); @@ -6178,7 +6184,7 @@ impl Channel { && info.next_holder_htlc_id == self.context.next_holder_htlc_id && info.next_counterparty_htlc_id == self.context.next_counterparty_htlc_id && info.feerate == self.context.feerate_per_kw { - let actual_fee = Self::commit_tx_fee_msat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.opt_anchors()); + let actual_fee = commit_tx_fee_msat(self.context.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.context.opt_anchors()); assert_eq!(actual_fee, info.fee); } } @@ -7274,7 +7280,7 @@ mod tests { use crate::ln::channelmanager::{self, HTLCSource, PaymentId}; #[cfg(anchors)] use crate::ln::channel::InitFeatures; - use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator}; + use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat}; use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; use crate::ln::features::ChannelTypeFeatures; use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; @@ -7473,16 +7479,16 @@ mod tests { // 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 = Channel::::commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.opt_anchors()); + let local_commit_tx_fee = node_a_chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None); + let local_commit_fee_0_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 0, node_a_chan.context.opt_anchors()); 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.context.channel_transaction_parameters.is_outbound_from_holder = false; - let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.opt_anchors()); + let remote_commit_fee_3_htlcs = commit_tx_fee_msat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.opt_anchors()); 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); + let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs); } @@ -7502,20 +7508,20 @@ mod tests { let config = UserConfig::default(); let mut chan = Channel::::new_outbound(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap(); - let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.context.feerate_per_kw, 0, chan.context.opt_anchors()); - let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.context.feerate_per_kw, 1, chan.context.opt_anchors()); + let commitment_tx_fee_0_htlcs = commit_tx_fee_msat(chan.context.feerate_per_kw, 0, chan.context.opt_anchors()); + let commitment_tx_fee_1_htlc = commit_tx_fee_msat(chan.context.feerate_per_kw, 1, chan.context.opt_anchors()); // 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(chan.context.opt_anchors()) / 1000) + chan.context.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); + let commitment_tx_fee = chan.context.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(chan.context.opt_anchors()) / 1000) + chan.context.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); + let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs); chan.context.channel_transaction_parameters.is_outbound_from_holder = false; @@ -7523,13 +7529,13 @@ mod tests { // 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(chan.context.opt_anchors()) / 1000) + chan.context.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); + let commitment_tx_fee = chan.context.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(chan.context.opt_anchors()) / 1000) + chan.context.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); + let commitment_tx_fee = chan.context.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc); }