X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=d76840236a1b04945de7703eae62906a6ddd4469;hb=1b88f1638e5d743dc827b5f0e1ccd35f00b69907;hp=fcb13031ac62274146e8461cb13fa17d5278be21;hpb=efd9ad22fc7d7c3ab131a7fc08b2aa1e1f46c1c0;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index fcb13031a..d76840236 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -294,6 +294,7 @@ struct HTLCStats { on_counterparty_tx_dust_exposure_msat: u64, on_holder_tx_dust_exposure_msat: u64, holding_cell_msat: u64, + on_holder_tx_holding_cell_htlcs_count: u32, // dust HTLCs *non*-included } /// An enum gathering stats on commitment transaction, either local or remote. @@ -405,7 +406,12 @@ pub(crate) const FUNDING_CONF_DEADLINE_BLOCKS: u32 = 2016; /// size 2. However, if the number of concurrent update_add_htlc is higher, this still /// leads to a channel force-close. Ultimately, this is an issue coming from the /// design of LN state machines, allowing asynchronous updates. -const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2; +pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2; + +/// When a channel is opened, we check that the funding amount is enough to pay for relevant +/// commitment transaction fees, with at least this many HTLCs present on the commitment +/// transaction (not counting the value of the HTLCs themselves). +pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4; // 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 @@ -678,6 +684,10 @@ impl Channel { cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO } + pub(crate) fn opt_anchors(&self) -> bool { + self.channel_transaction_parameters.opt_anchors.is_some() + } + // Constructors: pub fn new_outbound( fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, @@ -707,6 +717,12 @@ impl Channel { let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + 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); + 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(&keys_provider.get_secure_random_bytes()); @@ -737,7 +753,7 @@ impl Channel { cur_holder_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, cur_counterparty_commitment_transaction_number: INITIAL_COMMITMENT_NUMBER, - value_to_self_msat: channel_value_satoshis * 1000 - push_msat, + value_to_self_msat, pending_inbound_htlcs: Vec::new(), pending_outbound_htlcs: Vec::new(), @@ -789,7 +805,8 @@ impl Channel { holder_selected_contest_delay: config.own_channel_config.our_to_self_delay, is_outbound_from_holder: true, counterparty_parameters: None, - funding_outpoint: None + funding_outpoint: None, + opt_anchors: None, }, funding_transaction: None, @@ -951,8 +968,6 @@ impl Channel { // we either accept their preference or the preferences match local_config.announced_channel = announce; - let background_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background); - let holder_selected_channel_reserve_satoshis = Channel::::get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis); if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { return Err(ChannelError::Close(format!("Suitable channel reserve not found. remote_channel_reserve was ({}). dust_limit_satoshis is ({}).", holder_selected_channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS))); @@ -965,17 +980,18 @@ impl Channel { } // check if the funder's amount for the initial commitment tx is sufficient - // for full fee payment + // 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 lower_limit = background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT; - if funders_amount_msat < lower_limit { - return Err(ChannelError::Close(format!("Insufficient funding amount ({}) for initial commitment. Must be at least {}", funders_amount_msat, lower_limit))); + let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT) / 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))); } - let to_local_msat = msg.push_msat; - let to_remote_msat = funders_amount_msat - background_feerate as u64 * COMMITMENT_TX_BASE_WEIGHT; - if to_local_msat <= msg.channel_reserve_satoshis * 1000 && to_remote_msat <= holder_selected_channel_reserve_satoshis * 1000 { - return Err(ChannelError::Close("Insufficient funding amount for initial commitment".to_owned())); + let to_remote_satoshis = funders_amount_msat / 1000 - commitment_tx_fee; + // While it's reasonable for us to not meet the channel reserve initially (if they don't + // want to push much to us), our counterparty should always have more than our reserve. + if to_remote_satoshis < holder_selected_channel_reserve_satoshis { + return Err(ChannelError::Close("Insufficient funding amount for initial reserve".to_owned())); } let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { @@ -1083,7 +1099,8 @@ impl Channel { selected_contest_delay: msg.to_self_delay, pubkeys: counterparty_pubkeys, }), - funding_outpoint: None + funding_outpoint: None, + opt_anchors: None }, funding_transaction: None, @@ -1310,7 +1327,7 @@ impl Channel { let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, value_to_a as u64, value_to_b as u64, - false, + self.channel_transaction_parameters.opt_anchors.is_some(), funding_pubkey_a, funding_pubkey_b, keys.clone(), @@ -2024,6 +2041,7 @@ impl Channel { 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, }; let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; @@ -2048,6 +2066,7 @@ impl Channel { 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, }; let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; @@ -2072,6 +2091,8 @@ impl Channel { } 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; } } } @@ -2104,10 +2125,10 @@ impl Channel { // 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(&self, num_htlcs: usize) -> u64 { + fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize) -> 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 + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * self.feerate_per_kw as u64 / 1000 * 1000 + (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 } // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. @@ -2181,12 +2202,12 @@ impl Channel { } let num_htlcs = included_htlcs + addl_htlcs; - let res = self.commit_tx_fee_msat(num_htlcs); + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs); #[cfg(any(test, feature = "fuzztarget"))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = self.commit_tx_fee_msat(num_htlcs - 1); + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + self.holding_cell_htlc_updates.len(); @@ -2259,12 +2280,12 @@ impl Channel { } let num_htlcs = included_htlcs + addl_htlcs; - let res = self.commit_tx_fee_msat(num_htlcs); + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs); #[cfg(any(test, feature = "fuzztarget"))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = self.commit_tx_fee_msat(num_htlcs - 1); + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let commitment_tx_info = CommitmentTxInfoCached { @@ -2570,10 +2591,10 @@ impl Channel { for (idx, (htlc, source)) in htlcs_cloned.drain(..).enumerate() { if let Some(_) = htlc.transaction_output_index { let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw, - self.get_counterparty_selected_contest_delay().unwrap(), &htlc, + self.get_counterparty_selected_contest_delay().unwrap(), &htlc, self.opt_anchors(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys); + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]); log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.", log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()), @@ -3099,7 +3120,7 @@ impl Channel { let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw)); let keys = if let Ok(keys) = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number) { keys } else { return None; }; let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger); - let buffer_fee_msat = Channel::::commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize) * 1000; + let buffer_fee_msat = Channel::::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) * 1000; let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat; if holder_balance_msat < buffer_fee_msat + self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 { //TODO: auto-close after a number of failures? @@ -4891,7 +4912,7 @@ impl Channel { && info.next_holder_htlc_id == self.next_holder_htlc_id && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id && info.feerate == self.feerate_per_kw { - let actual_fee = self.commit_tx_fee_msat(commitment_stats.num_nondust_htlcs); + let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs); assert_eq!(actual_fee, info.fee); } } @@ -4916,8 +4937,8 @@ impl Channel { for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) { log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}", - encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), - encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &counterparty_keys)), + encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, self.opt_anchors(), &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), + encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &counterparty_keys)), log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()), log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.channel_id())); } @@ -5621,6 +5642,11 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel return Err(DecodeError::UnknownRequiredFeature); } + if channel_parameters.opt_anchors.is_some() { + // Relax this check when ChannelTypeFeatures supports anchors. + return Err(DecodeError::InvalidValue); + } + let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes()); @@ -5916,13 +5942,13 @@ mod tests { // the dust limit check. let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None); - let local_commit_fee_0_htlcs = node_a_chan.commit_tx_fee_msat(0); + let local_commit_fee_0_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0); assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs); // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all // of the HTLCs are seen to be above the dust limit. node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false; - let remote_commit_fee_3_htlcs = node_a_chan.commit_tx_fee_msat(3); + let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3); let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs); @@ -5944,8 +5970,8 @@ mod tests { let config = UserConfig::default(); let mut chan = Channel::::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap(); - let commitment_tx_fee_0_htlcs = chan.commit_tx_fee_msat(0); - let commitment_tx_fee_1_htlc = chan.commit_tx_fee_msat(1); + let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0); + let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1); // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be // counted as dust when it shouldn't be. @@ -6207,10 +6233,11 @@ mod tests { let remote_signature = Signature::from_der(&hex::decode($counterparty_htlc_sig_hex).unwrap()[..]).unwrap(); let ref htlc = htlcs[$htlc_idx]; + let opt_anchors = false; let htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.feerate_per_kw, chan.get_counterparty_selected_contest_delay().unwrap(), - &htlc, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys); + &htlc, opt_anchors, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys); let htlc_sighash = Message::from_slice(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, SigHashType::All)[..]).unwrap(); secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).unwrap();