X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=43032c51a3c09cdc67988e96050835fd7a17d9d7;hb=6d8be70c6f761ccc58dd84b3abbb35d4c57c06d0;hp=60ff1ded1ad99220686729be383ea8967869ec68;hpb=92c87bae199b666f1f212b2b91accb5712490885;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 60ff1ded..43032c51 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -8,8 +8,8 @@ // licenses. use bitcoin::blockdata::script::{Script,Builder}; -use bitcoin::blockdata::transaction::{Transaction, SigHashType}; -use bitcoin::util::bip143; +use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType}; +use bitcoin::util::sighash; use bitcoin::consensus::encode; use bitcoin::hashes::Hash; @@ -18,8 +18,8 @@ use bitcoin::hashes::sha256d::Hash as Sha256d; use bitcoin::hash_types::{Txid, BlockHash}; use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE; -use bitcoin::secp256k1::key::{PublicKey,SecretKey}; -use bitcoin::secp256k1::{Secp256k1,Signature}; +use bitcoin::secp256k1::{PublicKey,SecretKey}; +use bitcoin::secp256k1::{Secp256k1,ecdsa::Signature}; use bitcoin::secp256k1; use ln::{PaymentPreimage, PaymentHash}; @@ -39,7 +39,7 @@ use util::events::ClosureReason; use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter}; use util::logger::Logger; use util::errors::APIError; -use util::config::{UserConfig, ChannelConfig, ChannelHandshakeLimits}; +use util::config::{UserConfig, ChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits}; use util::scid_utils::scid_from_parts; use io; @@ -62,6 +62,17 @@ pub struct ChannelValueStat { pub counterparty_dust_limit_msat: u64, } +pub struct AvailableBalances { + /// The amount that would go to us if we close the channel, ignoring any on-chain fees. + pub balance_msat: u64, + /// Total amount available for our counterparty to send to us. + pub inbound_capacity_msat: u64, + /// Total amount available for us to send to our counterparty. + pub outbound_capacity_msat: u64, + /// The maximum value we can assign to the next outbound HTLC + pub next_outbound_htlc_limit_msat: u64, +} + #[derive(Debug, Clone, Copy, PartialEq)] enum FeeUpdateState { // Inbound states mirroring InboundHTLCState @@ -734,9 +745,19 @@ pub const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; pub const ANCHOR_OUTPUT_VALUE_SATOSHI: u64 = 330; -/// Maximum `funding_satoshis` value, according to the BOLT #2 specification -/// it's 2^24. -pub const MAX_FUNDING_SATOSHIS: u64 = 1 << 24; +/// 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; + +/// 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; + +/// Total bitcoin supply in satoshis. +pub const TOTAL_BITCOIN_SUPPLY_SATOSHIS: u64 = 21_000_000 * 1_0000_0000; /// 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 @@ -788,9 +809,22 @@ macro_rules! secp_check { } impl Channel { - // Convert constants + channel value to limits: - fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 { - channel_value_satoshis * 1000 / 10 //TODO + /// 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, @@ -850,8 +884,11 @@ impl Channel { let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis); let pubkeys = holder_signer.pubkeys().clone(); - if channel_value_satoshis >= MAX_FUNDING_SATOSHIS { - return Err(APIError::APIMisuseError{err: format!("funding_value must be smaller than {}, it was {}", MAX_FUNDING_SATOSHIS, channel_value_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)}); + } + 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 { @@ -946,7 +983,7 @@ impl Channel { counterparty_dust_limit_satoshis: 0, holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS, counterparty_max_htlc_value_in_flight_msat: 0, - holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis), + holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.own_channel_config), counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel holder_selected_channel_reserve_satoshis, counterparty_htlc_minimum_msat: 0, @@ -1076,8 +1113,11 @@ impl Channel { } // Check sanity of message fields: - if msg.funding_satoshis >= MAX_FUNDING_SATOSHIS { - return Err(ChannelError::Close(format!("Funding must be smaller than {}. It was {}", MAX_FUNDING_SATOSHIS, msg.funding_satoshis))); + if msg.funding_satoshis > config.peer_channel_config_limits.max_funding_satoshis { + return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.peer_channel_config_limits.max_funding_satoshis, msg.funding_satoshis))); + } + if msg.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS { + return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.funding_satoshis))); } if msg.channel_reserve_satoshis > msg.funding_satoshis { return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.funding_satoshis))); @@ -1261,7 +1301,7 @@ impl Channel { counterparty_dust_limit_satoshis: msg.dust_limit_satoshis, holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS, counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000), - holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis), + holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.own_channel_config), counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis), holder_selected_channel_reserve_satoshis, counterparty_htlc_minimum_msat: msg.htlc_minimum_msat, @@ -1906,6 +1946,10 @@ impl Channel { if msg.dust_limit_satoshis > self.holder_selected_channel_reserve_satoshis { return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.holder_selected_channel_reserve_satoshis))); } + if msg.channel_reserve_satoshis > self.channel_value_satoshis - self.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.channel_value_satoshis - self.holder_selected_channel_reserve_satoshis))); + } let full_channel_value_msat = (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000; if msg.htlc_minimum_msat >= full_channel_value_msat { return Err(ChannelError::Close(format!("Minimum htlc value ({}) is full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat))); @@ -2023,7 +2067,7 @@ impl Channel { log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.channel_id())); - secp_check!(self.secp_ctx.verify(&sighash, &sig, self.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned()); + secp_check!(self.secp_ctx.verify_ecdsa(&sighash, &sig, self.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned()); } let counterparty_keys = self.build_remote_transaction_keys()?; @@ -2155,7 +2199,7 @@ impl Channel { let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.channel_value_satoshis); // They sign our commitment transaction, allowing us to broadcast the tx if we wish. - if let Err(_) = self.secp_ctx.verify(&sighash, &msg.signature, &self.get_counterparty_pubkeys().funding_pubkey) { + if let Err(_) = self.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.get_counterparty_pubkeys().funding_pubkey) { return Err(ChannelError::Close("Invalid funding_signed signature from peer".to_owned())); } } @@ -2332,40 +2376,39 @@ impl Channel { stats } - /// Get the available (ie not including pending HTLCs) inbound and outbound balance in msat. + /// 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. - /// The channel reserve is subtracted from each balance. - /// See also [`Channel::get_balance_msat`] - pub fn get_inbound_outbound_available_balance_msat(&self) -> (u64, u64) { + pub fn get_available_balances(&self) -> AvailableBalances { // Note that we have to handle overflow due to the above case. - ( - cmp::max(self.channel_value_satoshis as i64 * 1000 - - self.value_to_self_msat as i64 - - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 - - self.holder_selected_channel_reserve_satoshis as i64 * 1000, - 0) as u64, - cmp::max(self.value_to_self_msat as i64 - - self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 - - self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000, - 0) as u64 - ) - } + let outbound_stats = self.get_outbound_pending_htlc_stats(None); - /// Get our total balance in msat. - /// This is the amount that would go to us if we close the channel, ignoring any on-chain fees. - /// See also [`Channel::get_inbound_outbound_available_balance_msat`] - pub fn get_balance_msat(&self) -> u64 { - // Include our local balance, plus any inbound HTLCs we know the preimage for, minus any - // HTLCs sent or which will be sent after commitment signed's are exchanged. let mut balance_msat = self.value_to_self_msat; for ref htlc in self.pending_inbound_htlcs.iter() { if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) = htlc.state { balance_msat += htlc.amount_msat; } } - balance_msat - self.get_outbound_pending_htlc_stats(None).pending_htlcs_value_msat + balance_msat -= outbound_stats.pending_htlcs_value_msat; + + let outbound_capacity_msat = cmp::max(self.value_to_self_msat as i64 + - outbound_stats.pending_htlcs_value_msat as i64 + - self.counterparty_selected_channel_reserve_satoshis.unwrap_or(0) as i64 * 1000, + 0) as u64; + AvailableBalances { + inbound_capacity_msat: cmp::max(self.channel_value_satoshis as i64 * 1000 + - self.value_to_self_msat as i64 + - self.get_inbound_pending_htlc_stats(None).pending_htlcs_value_msat as i64 + - self.holder_selected_channel_reserve_satoshis as i64 * 1000, + 0) as u64, + outbound_capacity_msat, + next_outbound_htlc_limit_msat: cmp::max(cmp::min(outbound_capacity_msat as i64, + self.counterparty_max_htlc_value_in_flight_msat as i64 + - outbound_stats.pending_htlcs_value_msat as i64), + 0) as u64, + balance_msat, + } } pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option) { @@ -2794,7 +2837,7 @@ impl Channel { log_bytes!(msg.signature.serialize_compact()[..]), log_bytes!(self.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction), log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.channel_id())); - if let Err(_) = self.secp_ctx.verify(&sighash, &msg.signature, &self.counterparty_funding_pubkey()) { + if let Err(_) = self.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.counterparty_funding_pubkey()) { return Err((None, ChannelError::Close("Invalid commitment tx signature from peer".to_owned()))); } bitcoin_tx.txid @@ -2844,12 +2887,12 @@ impl Channel { &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); - let htlc_sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All }; - let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]); + let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); 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()), encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), log_bytes!(self.channel_id())); - if let Err(_) = self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key) { + if let Err(_) = self.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key) { return Err((None, ChannelError::Close("Invalid HTLC tx signature from peer".to_owned()))); } htlcs_and_sigs.push((htlc, Some(msg.htlc_signatures[idx]), source)); @@ -3717,6 +3760,15 @@ impl Channel { } } + // Before we change the state of the channel, we check if the peer is sending a very old + // commitment transaction number, if yes we send a warning message. + let our_commitment_transaction = INITIAL_COMMITMENT_NUMBER - self.cur_holder_commitment_transaction_number - 1; + if msg.next_remote_commitment_number + 1 < our_commitment_transaction { + return Err( + ChannelError::Warn(format!("Peer attempted to reestablish channel with a very old local commitment transaction: {} (received) vs {} (expected)", msg.next_remote_commitment_number, our_commitment_transaction)) + ); + } + // Go ahead and unmark PeerDisconnected as various calls we may make check for it (and all // remaining cases either succeed or ErrorMessage-fail). self.channel_state &= !(ChannelState::PeerDisconnected as u32); @@ -4086,15 +4138,17 @@ impl Channel { let funding_key = self.get_holder_pubkeys().funding_pubkey.serialize(); let counterparty_funding_key = self.counterparty_funding_pubkey().serialize(); + let mut holder_sig = sig.serialize_der().to_vec(); + holder_sig.push(EcdsaSighashType::All as u8); + let mut cp_sig = counterparty_sig.serialize_der().to_vec(); + cp_sig.push(EcdsaSighashType::All as u8); if funding_key[..] < counterparty_funding_key[..] { - tx.input[0].witness.push(sig.serialize_der().to_vec()); - tx.input[0].witness.push(counterparty_sig.serialize_der().to_vec()); + tx.input[0].witness.push(holder_sig); + tx.input[0].witness.push(cp_sig); } else { - tx.input[0].witness.push(counterparty_sig.serialize_der().to_vec()); - tx.input[0].witness.push(sig.serialize_der().to_vec()); + tx.input[0].witness.push(cp_sig); + tx.input[0].witness.push(holder_sig); } - tx.input[0].witness[1].push(SigHashType::All as u8); - tx.input[0].witness[2].push(SigHashType::All as u8); tx.input[0].witness.push(self.get_funding_redeemscript().into_bytes()); tx @@ -4112,7 +4166,7 @@ impl Channel { if !self.pending_inbound_htlcs.is_empty() || !self.pending_outbound_htlcs.is_empty() { return Err(ChannelError::Close("Remote end sent us a closing_signed while there were still pending HTLCs".to_owned())); } - if msg.fee_satoshis > 21_000_000 * 1_0000_0000 { //this is required to stop potential overflow in build_closing_transaction + if msg.fee_satoshis > TOTAL_BITCOIN_SUPPLY_SATOSHIS { // this is required to stop potential overflow in build_closing_transaction return Err(ChannelError::Close("Remote tried to send us a closing tx with > 21 million BTC fee".to_owned())); } @@ -4132,14 +4186,14 @@ impl Channel { } let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.channel_value_satoshis); - match self.secp_ctx.verify(&sighash, &msg.signature, &self.get_counterparty_pubkeys().funding_pubkey) { + match self.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.get_counterparty_pubkeys().funding_pubkey) { Ok(_) => {}, Err(_e) => { // The remote end may have decided to revoke their output due to inconsistent dust // limits, so check for that case by re-checking the signature here. closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0; let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.channel_value_satoshis); - secp_check!(self.secp_ctx.verify(&sighash, &msg.signature, self.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); + secp_check!(self.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); }, }; @@ -4340,7 +4394,7 @@ impl Channel { // channel might have been used to route very small values (either by honest users or as DoS). self.channel_value_satoshis * 1000 * 9 / 10, - self.holder_max_htlc_value_in_flight_msat + self.counterparty_max_htlc_value_in_flight_msat ); } @@ -4700,10 +4754,14 @@ impl Channel { } // If we've sent funding_locked (or have both sent and received funding_locked), and - // the funding transaction's confirmation count has dipped below minimum_depth / 2, + // the funding transaction has become unconfirmed, // close the channel and hope we can get the latest state on chain (because presumably // the funding transaction is at least still in the mempool of most nodes). - if funding_tx_confirmations < self.minimum_depth.unwrap() as i64 / 2 { + // + // Note that ideally we wouldn't force-close if we see *any* reorg on a 1-conf channel, + // but not doing so may lead to the `ChannelManager::short_to_id` map being + // inconsistent, so we currently have to. + if funding_tx_confirmations == 0 && self.funding_tx_confirmed_in.is_some() { let err_reason = format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth.unwrap(), funding_tx_confirmations); return Err(ClosureReason::ProcessingError { err: err_reason }); @@ -5025,12 +5083,12 @@ impl Channel { let msghash = hash_to_message!(&Sha256d::hash(&announcement.encode()[..])[..]); - if self.secp_ctx.verify(&msghash, &msg.node_signature, &self.get_counterparty_node_id()).is_err() { + if self.secp_ctx.verify_ecdsa(&msghash, &msg.node_signature, &self.get_counterparty_node_id()).is_err() { return Err(ChannelError::Close(format!( "Bad announcement_signatures. Failed to verify node_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_node_key is {:?}", &announcement, self.get_counterparty_node_id()))); } - if self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, self.counterparty_funding_pubkey()).is_err() { + if self.secp_ctx.verify_ecdsa(&msghash, &msg.bitcoin_signature, self.counterparty_funding_pubkey()).is_err() { return Err(ChannelError::Close(format!( "Bad announcement_signatures. Failed to verify bitcoin_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_bitcoin_key is ({:?})", &announcement, self.counterparty_funding_pubkey()))); @@ -5857,13 +5915,18 @@ impl Writeable for Channel { let chan_type = if self.channel_type != ChannelTypeFeatures::only_static_remote_key() { Some(&self.channel_type) } else { None }; - // The same logic applies for `holder_selected_channel_reserve_satoshis` and - // `holder_max_htlc_value_in_flight_msat` values other than the defaults. + // The same logic applies for `holder_selected_channel_reserve_satoshis` values other than + // the default, and when `holder_max_htlc_value_in_flight_msat` is configured to be set to + // a different percentage of the channel value then 10%, which older versions of LDK used + // to set it to before the percentage was made configurable. let serialized_holder_selected_reserve = if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) { Some(self.holder_selected_channel_reserve_satoshis) } else { None }; + + let mut old_max_in_flight_percent_config = UserConfig::default().own_channel_config; + old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = MAX_IN_FLIGHT_PERCENT_LEGACY; let serialized_holder_htlc_max_in_flight = - if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis) + if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis, &old_max_in_flight_percent_config) { Some(self.holder_max_htlc_value_in_flight_msat) } else { None }; write_tlv_fields!(writer, { @@ -6133,7 +6196,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel let mut target_closing_feerate_sats_per_kw = None; let mut monitor_pending_finalized_fulfills = Some(Vec::new()); let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis)); - let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis)); + let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().own_channel_config)); // Prior to supporting channel type negotiation, all of our channels were static_remotekey // only, so we default to that if none was written. let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key()); @@ -6319,7 +6382,7 @@ mod tests { use ln::PaymentHash; use ln::channelmanager::{HTLCSource, PaymentId}; use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator}; - use ln::channel::MAX_FUNDING_SATOSHIS; + use ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS}; use ln::features::InitFeatures; use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate}; use ln::script::ShutdownScript; @@ -6334,15 +6397,15 @@ mod tests { use util::errors::APIError; use util::test_utils; use util::test_utils::OnGetShutdownScriptpubkey; - use bitcoin::secp256k1::{Secp256k1, Signature}; + use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; use bitcoin::secp256k1::ffi::Signature as FFISignature; - use bitcoin::secp256k1::key::{SecretKey,PublicKey}; - use bitcoin::secp256k1::recovery::RecoverableSignature; + use bitcoin::secp256k1::{SecretKey,PublicKey}; + use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::hash_types::WPubkeyHash; - use core::num::NonZeroU8; use bitcoin::bech32::u5; + use bitcoin::util::address::WitnessVersion; use prelude::*; struct TestFeeEstimator { @@ -6355,9 +6418,10 @@ mod tests { } #[test] - fn test_max_funding_satoshis() { - assert!(MAX_FUNDING_SATOSHIS <= 21_000_000 * 100_000_000, - "MAX_FUNDING_SATOSHIS is greater than all satoshis in existence"); + fn test_max_funding_satoshis_no_wumbo() { + assert_eq!(TOTAL_BITCOIN_SUPPLY_SATOSHIS, 21_000_000 * 100_000_000); + assert!(MAX_FUNDING_SATOSHIS_NO_WUMBO <= TOTAL_BITCOIN_SUPPLY_SATOSHIS, + "MAX_FUNDING_SATOSHIS_NO_WUMBO is greater than all satoshis in existence"); } #[test] @@ -6405,7 +6469,7 @@ mod tests { fn upfront_shutdown_script_incompatibility() { let features = InitFeatures::known().clear_shutdown_anysegwit(); let non_v0_segwit_shutdown_script = - ShutdownScript::new_witness_program(NonZeroU8::new(16).unwrap(), &[0, 40]).unwrap(); + ShutdownScript::new_witness_program(WitnessVersion::V16, &[0, 40]).unwrap(); let seed = [42; 32]; let network = Network::Testnet; @@ -6635,6 +6699,79 @@ mod tests { } } + #[test] + fn test_configured_holder_max_htlc_value_in_flight() { + let feeest = TestFeeEstimator{fee_est: 15000}; + let logger = test_utils::TestLogger::new(); + let secp_ctx = Secp256k1::new(); + let seed = [42; 32]; + let network = Network::Testnet; + let keys_provider = test_utils::TestKeysInterface::new(&seed, network); + let outbound_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); + let inbound_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); + + let mut config_2_percent = UserConfig::default(); + config_2_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 2; + let mut config_99_percent = UserConfig::default(); + config_99_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 99; + let mut config_0_percent = UserConfig::default(); + config_0_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 0; + let mut config_101_percent = UserConfig::default(); + config_101_percent.own_channel_config.max_inbound_htlc_value_in_flight_percent_of_channel = 101; + + // Test that `new_outbound` creates a channel with the correct value for + // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value, + // which is set to the lower bound + 1 (2%) of the `channel_value`. + let chan_1 = Channel::::new_outbound(&&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_2_percent, 0, 42).unwrap(); + let chan_1_value_msat = chan_1.channel_value_satoshis * 1000; + assert_eq!(chan_1.holder_max_htlc_value_in_flight_msat, (chan_1_value_msat as f64 * 0.02) as u64); + + // Test with the upper bound - 1 of valid values (99%). + let chan_2 = Channel::::new_outbound(&&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_99_percent, 0, 42).unwrap(); + let chan_2_value_msat = chan_2.channel_value_satoshis * 1000; + assert_eq!(chan_2.holder_max_htlc_value_in_flight_msat, (chan_2_value_msat as f64 * 0.99) as u64); + + let chan_1_open_channel_msg = chan_1.get_open_channel(genesis_block(network).header.block_hash()); + + // Test that `new_from_req` creates a channel with the correct value for + // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value, + // which is set to the lower bound - 1 (2%) of the `channel_value`. + let chan_3 = Channel::::new_from_req(&&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_2_percent, 0, &&logger, 42).unwrap(); + let chan_3_value_msat = chan_3.channel_value_satoshis * 1000; + assert_eq!(chan_3.holder_max_htlc_value_in_flight_msat, (chan_3_value_msat as f64 * 0.02) as u64); + + // Test with the upper bound - 1 of valid values (99%). + let chan_4 = Channel::::new_from_req(&&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_99_percent, 0, &&logger, 42).unwrap(); + let chan_4_value_msat = chan_4.channel_value_satoshis * 1000; + assert_eq!(chan_4.holder_max_htlc_value_in_flight_msat, (chan_4_value_msat as f64 * 0.99) as u64); + + // Test that `new_outbound` uses the lower bound of the configurable percentage values (1%) + // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. + let chan_5 = Channel::::new_outbound(&&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_0_percent, 0, 42).unwrap(); + let chan_5_value_msat = chan_5.channel_value_satoshis * 1000; + assert_eq!(chan_5.holder_max_htlc_value_in_flight_msat, (chan_5_value_msat as f64 * 0.01) as u64); + + // Test that `new_outbound` uses the upper bound of the configurable percentage values + // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value + // than 100. + let chan_6 = Channel::::new_outbound(&&feeest, &&keys_provider, outbound_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config_101_percent, 0, 42).unwrap(); + let chan_6_value_msat = chan_6.channel_value_satoshis * 1000; + assert_eq!(chan_6.holder_max_htlc_value_in_flight_msat, chan_6_value_msat); + + // Test that `new_from_req` uses the lower bound of the configurable percentage values (1%) + // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. + let chan_7 = Channel::::new_from_req(&&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_0_percent, 0, &&logger, 42).unwrap(); + let chan_7_value_msat = chan_7.channel_value_satoshis * 1000; + assert_eq!(chan_7.holder_max_htlc_value_in_flight_msat, (chan_7_value_msat as f64 * 0.01) as u64); + + // Test that `new_from_req` uses the upper bound of the configurable percentage values + // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value + // than 100. + let chan_8 = Channel::::new_from_req(&&feeest, &&keys_provider, inbound_node_id, &InitFeatures::known(), &chan_1_open_channel_msg, 7, &config_101_percent, 0, &&logger, 42).unwrap(); + let chan_8_value_msat = chan_8.channel_value_satoshis * 1000; + assert_eq!(chan_8.holder_max_htlc_value_in_flight_msat, chan_8_value_msat); + } + #[test] fn channel_update() { let feeest = TestFeeEstimator{fee_est: 15000}; @@ -6686,9 +6823,9 @@ mod tests { #[cfg(not(feature = "grind_signatures"))] #[test] fn outbound_commitment_test() { - use bitcoin::util::bip143; + use bitcoin::util::sighash; use bitcoin::consensus::encode::serialize; - use bitcoin::blockdata::transaction::SigHashType; + use bitcoin::blockdata::transaction::EcdsaSighashType; use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::Txid; use bitcoin::secp256k1::Message; @@ -6797,7 +6934,7 @@ mod tests { let counterparty_signature = Signature::from_der(&hex::decode($counterparty_sig_hex).unwrap()[..]).unwrap(); let sighash = unsigned_tx.get_sighash_all(&redeemscript, chan.channel_value_satoshis); log_trace!(logger, "unsigned_tx = {}", hex::encode(serialize(&unsigned_tx.transaction))); - assert!(secp_ctx.verify(&sighash, &counterparty_signature, chan.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig"); + assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig"); let mut per_htlc: Vec<(HTLCOutputInCommitment, Option)> = Vec::new(); per_htlc.clear(); // Don't warn about excess mut for no-HTLC calls @@ -6836,9 +6973,9 @@ mod tests { chan.get_counterparty_selected_contest_delay().unwrap(), &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_sighashtype = if $opt_anchors { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All }; - let htlc_sighash = Message::from_slice(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]).unwrap(); - assert!(secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).is_ok(), "verify counterparty htlc sig"); + let htlc_sighashtype = if $opt_anchors { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_sighash = Message::from_slice(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]).unwrap(); + assert!(secp_ctx.verify_ecdsa(&htlc_sighash, &remote_signature, &keys.countersignatory_htlc_key).is_ok(), "verify counterparty htlc sig"); let mut preimage: Option = None; if !htlc.offered {