X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=0ab687521c3aa5fcff317b1c53ee65e58022dcda;hb=d5e70ad185137d2b23744aeaaa0116a0b5b80372;hp=e39478bd740c063ce1f29a7dc853238ec75fcf48;hpb=081ce7c843713a42803097a6d2dcf3631778beda;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index e39478bd..0ab68752 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -32,9 +32,10 @@ use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputIn use ln::chan_utils; use chain::BestBlock; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; -use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER}; +use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS}; use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::{Sign, KeysInterface}; +use util::events::ClosureReason; use util::ser::{Readable, ReadableArgs, Writeable, Writer, VecWriter}; use util::logger::Logger; use util::errors::APIError; @@ -61,7 +62,7 @@ pub struct ChannelValueStat { pub counterparty_dust_limit_msat: u64, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] enum FeeUpdateState { // Inbound states mirroring InboundHTLCState RemoteAnnounced, @@ -292,6 +293,19 @@ struct HTLCStats { pending_htlcs_value_msat: u64, 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. +struct CommitmentStats<'a> { + tx: CommitmentTransaction, // the transaction info + feerate_per_kw: u32, // the feerate included to build the transaction + total_fee_sat: u64, // the total fee included in the transaction + num_nondust_htlcs: usize, // the number of HTLC outputs (dust HTLCs *non*-included) + htlcs_included: Vec<(HTLCOutputInCommitment, Option<&'a HTLCSource>)>, // the list of HTLCs (dust HTLCs *included*) which were not ignored when building the transaction + local_balance_msat: u64, // local balance before fees but considering dust limits + remote_balance_msat: u64, // remote balance before fees but considering dust limits } /// Used when calculating whether we or the remote can afford an additional HTLC. @@ -373,11 +387,32 @@ pub(super) struct MonitorRestoreUpdates { /// the channel. Sadly, there isn't really a good number for this - if we expect to have no new /// HTLCs for days we may need this to suffice for feerate increases across days, but that may /// leave the channel less usable as we hold a bigger reserve. -#[cfg(fuzzing)] +#[cfg(any(fuzzing, test))] pub const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2; -#[cfg(not(fuzzing))] +#[cfg(not(any(fuzzing, test)))] const FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE: u64 = 2; +/// If we fail to see a funding transaction confirmed on-chain within this many blocks after the +/// channel creation on an inbound channel, we simply force-close and move on. +/// This constant is the one suggested in BOLT 2. +pub(crate) const FUNDING_CONF_DEADLINE_BLOCKS: u32 = 2016; + +/// In case of a concurrent update_add_htlc proposed by our counterparty, we might +/// not have enough balance value remaining to cover the onchain cost of this new +/// HTLC weight. If this happens, our counterparty fails the reception of our +/// commitment_signed including this new HTLC due to infringement on the channel +/// reserve. +/// To prevent this case, we compute our outbound update_fee with an HTLC buffer of +/// 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. +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 // calling channel_id() before we're set up or things like get_outbound_funding_signed on an @@ -475,20 +510,36 @@ pub(super) struct Channel { funding_tx_confirmed_in: Option, funding_tx_confirmation_height: u32, short_channel_id: Option, + /// Either the height at which this channel was created or the height at which it was last + /// serialized if it was serialized by versions prior to 0.0.103. + /// We use this to close if funding is never broadcasted. + channel_creation_height: u32, counterparty_dust_limit_satoshis: u64, + #[cfg(test)] pub(super) holder_dust_limit_satoshis: u64, #[cfg(not(test))] holder_dust_limit_satoshis: u64, + #[cfg(test)] pub(super) counterparty_max_htlc_value_in_flight_msat: u64, #[cfg(not(test))] counterparty_max_htlc_value_in_flight_msat: u64, - //get_holder_max_htlc_value_in_flight_msat(): u64, + + #[cfg(test)] + pub(super) holder_max_htlc_value_in_flight_msat: u64, + #[cfg(not(test))] + holder_max_htlc_value_in_flight_msat: u64, + /// minimum channel reserve for self to maintain - set by them. counterparty_selected_channel_reserve_satoshis: Option, - // get_holder_selected_channel_reserve_satoshis(channel_value_sats: u64): u64 + + #[cfg(test)] + pub(super) holder_selected_channel_reserve_satoshis: u64, + #[cfg(not(test))] + holder_selected_channel_reserve_satoshis: u64, + counterparty_htlc_minimum_msat: u64, holder_htlc_minimum_msat: u64, #[cfg(test)] @@ -640,13 +691,24 @@ impl Channel { /// required by us. /// /// Guaranteed to return a value no larger than channel_value_satoshis + /// + /// This is used both for new channels and to figure out what reserve value we sent to peers + /// for channels serialized before we included our selected reserve value in the serialized + /// data explicitly. pub(crate) fn get_holder_selected_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 { let (q, _) = channel_value_satoshis.overflowing_div(100); cmp::min(channel_value_satoshis, cmp::max(q, 1000)) //TODO } + 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, channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig) -> Result, APIError> + pub fn new_outbound( + fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, + channel_value_satoshis: u64, push_msat: u64, user_id: u64, config: &UserConfig, current_chain_height: u32 + ) -> Result, APIError> where K::Target: KeysInterface, F::Target: FeeEstimator, { @@ -671,6 +733,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()); @@ -701,7 +769,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(), @@ -734,12 +802,15 @@ impl Channel { 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: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis), counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel + holder_selected_channel_reserve_satoshis, counterparty_htlc_minimum_msat: 0, holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat }, counterparty_max_accepted_htlcs: 0, @@ -752,7 +823,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, @@ -790,8 +862,12 @@ impl Channel { where F::Target: FeeEstimator { let lower_limit = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background); - if feerate_per_kw < lower_limit { - return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {}", feerate_per_kw, lower_limit))); + // Some fee estimators round up to the next full sat/vbyte (ie 250 sats per kw), causing + // occasional issues with feerate disagreements between an initiator that wants a feerate + // of 1.1 sat/vbyte and a receiver that wants 1.1 rounded up to 2. Thus, we always add 250 + // sat/kw before the comparison here. + if feerate_per_kw + 250 < lower_limit { + return Err(ChannelError::Close(format!("Peer's feerate much too low. Actual: {}. Our expected lower limit: {} (- 250)", feerate_per_kw, lower_limit))); } // We only bound the fee updates on the upper side to prevent completely absurd feerates, // always accepting up to 25 sat/vByte or 10x our fee estimator's "High Priority" fee. @@ -807,9 +883,13 @@ impl Channel { /// Creates a new channel from a remote sides' request for one. /// Assumes chain_hash has already been checked and corresponds with what we expect! - pub fn new_from_req(fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig) -> Result, ChannelError> + pub fn new_from_req( + fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, + msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L + ) -> Result, ChannelError> where K::Target: KeysInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { // First check the channel type is known, failing before we do anything else if we don't // support this channel type. @@ -857,9 +937,6 @@ impl Channel { if msg.dust_limit_satoshis > msg.funding_satoshis { return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis))); } - if msg.dust_limit_satoshis > msg.channel_reserve_satoshis { - return Err(ChannelError::Close(format!("Bogus; channel reserve ({}) is less than dust limit ({})", msg.channel_reserve_satoshis, msg.dust_limit_satoshis))); - } let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000; if msg.htlc_minimum_msat >= full_channel_value_msat { return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat))); @@ -911,31 +988,31 @@ 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))); } if msg.channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { - return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is smaller than our dust limit ({})", msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS))); + log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.", + msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS); } if holder_selected_channel_reserve_satoshis < msg.dust_limit_satoshis { return Err(ChannelError::Close(format!("Dust limit ({}) too high for the channel reserve we require the remote to keep ({})", msg.dust_limit_satoshis, holder_selected_channel_reserve_satoshis))); } // 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() { @@ -1020,13 +1097,16 @@ impl Channel { funding_tx_confirmed_in: None, funding_tx_confirmation_height: 0, short_channel_id: None, + channel_creation_height: current_chain_height, feerate_per_kw: msg.feerate_per_kw, channel_value_satoshis: msg.funding_satoshis, counterparty_dust_limit_satoshis: msg.dust_limit_satoshis, holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS, counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000), + holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis), counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis), + holder_selected_channel_reserve_satoshis, counterparty_htlc_minimum_msat: msg.htlc_minimum_msat, holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat }, counterparty_max_accepted_htlcs: msg.max_accepted_htlcs, @@ -1042,7 +1122,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, @@ -1088,12 +1169,10 @@ impl Channel { /// have not yet committed it. Such HTLCs will only be included in transactions which are being /// generated by the peer which proposed adding the HTLCs, and thus we need to understand both /// which peer generated this transaction and "to whom" this transaction flows. - /// Returns (the transaction info, the number of HTLC outputs which were present in the - /// transaction, the list of HTLCs which were not ignored when building the transaction). - /// Note that below-dust HTLCs are included in the fourth return value, but not the third, and - /// sources are provided only for outbound HTLCs in the fourth return value. #[inline] - fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, logger: &L) -> (CommitmentTransaction, u32, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) where L::Target: Logger { + fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, logger: &L) -> CommitmentStats + where L::Target: Logger + { let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new(); let num_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let mut included_non_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(num_htlcs); @@ -1212,13 +1291,13 @@ impl Channel { } } - let value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset; + let mut value_to_self_msat: i64 = (self.value_to_self_msat - local_htlc_total_msat) as i64 + value_to_self_msat_offset; assert!(value_to_self_msat >= 0); // Note that in case they have several just-awaiting-last-RAA fulfills in-progress (ie // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to // "violate" their reserve value by couting those against it. Thus, we have to convert // everything to i64 before subtracting as otherwise we can overflow. - let value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; + let mut value_to_remote_msat: i64 = (self.channel_value_satoshis * 1000) as i64 - (self.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; assert!(value_to_remote_msat >= 0); #[cfg(debug_assertions)] @@ -1232,15 +1311,15 @@ impl Channel { }; debug_assert!(broadcaster_max_commitment_tx_output.0 <= value_to_self_msat as u64 || value_to_self_msat / 1000 >= self.counterparty_selected_channel_reserve_satoshis.unwrap() as i64); broadcaster_max_commitment_tx_output.0 = cmp::max(broadcaster_max_commitment_tx_output.0, value_to_self_msat as u64); - debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64); + debug_assert!(broadcaster_max_commitment_tx_output.1 <= value_to_remote_msat as u64 || value_to_remote_msat / 1000 >= self.holder_selected_channel_reserve_satoshis as i64); broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64); } - let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (included_non_dust_htlcs.len() as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; + let total_fee_sat = Channel::::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len()); let (value_to_self, value_to_remote) = if self.is_outbound() { - (value_to_self_msat / 1000 - total_fee as i64, value_to_remote_msat / 1000) + (value_to_self_msat / 1000 - total_fee_sat as i64, value_to_remote_msat / 1000) } else { - (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee as i64) + (value_to_self_msat / 1000, value_to_remote_msat / 1000 - total_fee_sat as i64) }; let mut value_to_a = if local { value_to_self } else { value_to_remote }; @@ -1271,7 +1350,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(), @@ -1284,7 +1363,19 @@ impl Channel { htlcs_included.sort_unstable_by_key(|h| h.0.transaction_output_index.unwrap()); htlcs_included.append(&mut included_dust_htlcs); - (tx, feerate_per_kw, num_nondust_htlcs, htlcs_included) + // For the stats, trimmed-to-0 the value in msats accordingly + value_to_self_msat = if (value_to_self_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_self_msat }; + value_to_remote_msat = if (value_to_remote_msat * 1000) < broadcaster_dust_limit_satoshis as i64 { 0 } else { value_to_remote_msat }; + + CommitmentStats { + tx, + feerate_per_kw, + total_fee_sat, + num_nondust_htlcs, + htlcs_included, + local_balance_msat: value_to_self_msat as u64, + remote_balance_msat: value_to_remote_msat as u64, + } } #[inline] @@ -1635,12 +1726,8 @@ impl Channel { if msg.channel_reserve_satoshis > self.channel_value_satoshis { return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.channel_value_satoshis))); } - if msg.channel_reserve_satoshis < self.holder_dust_limit_satoshis { - return Err(ChannelError::Close(format!("Peer never wants payout outputs? channel_reserve_satoshis was ({}). dust_limit is ({})", msg.channel_reserve_satoshis, self.holder_dust_limit_satoshis))); - } - let remote_reserve = Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis); - if msg.dust_limit_satoshis > remote_reserve { - return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, remote_reserve))); + if msg.dust_limit_satoshis > self.holder_selected_channel_reserve_satoshis { + return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.holder_selected_channel_reserve_satoshis))); } let full_channel_value_msat = (self.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000; if msg.htlc_minimum_msat >= full_channel_value_msat { @@ -1738,7 +1825,7 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; - let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger).0; + let initial_commitment_tx = self.build_commitment_transaction(self.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(); @@ -1752,7 +1839,7 @@ impl Channel { } let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.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(); @@ -1863,7 +1950,7 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.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(); @@ -1871,7 +1958,7 @@ impl Channel { log_bytes!(self.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction)); let holder_signer = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; - let initial_commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).0; + let initial_commitment_tx = self.build_commitment_transaction(self.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(); @@ -1966,16 +2053,18 @@ impl Channel { } /// Returns a HTLCStats about inbound pending htlcs - fn get_inbound_pending_htlc_stats(&self) -> HTLCStats { + fn get_inbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { let mut stats = HTLCStats { pending_htlcs: self.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, }; - let counterparty_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; - let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; + 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; + let holder_dust_limit_success_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; for ref htlc in self.pending_inbound_htlcs.iter() { stats.pending_htlcs_value_msat += htlc.amount_msat; if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat { @@ -1989,16 +2078,18 @@ impl Channel { } /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell. - fn get_outbound_pending_htlc_stats(&self) -> HTLCStats { + fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option) -> HTLCStats { let mut stats = HTLCStats { pending_htlcs: self.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, }; - let counterparty_dust_limit_success_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; - let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; + 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; + let holder_dust_limit_timeout_sat = (self.get_dust_buffer_feerate(outbound_feerate_update) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; for ref htlc in self.pending_outbound_htlcs.iter() { stats.pending_htlcs_value_msat += htlc.amount_msat; if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat { @@ -2013,11 +2104,14 @@ impl Channel { 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; } } } @@ -2033,27 +2127,33 @@ impl Channel { ( cmp::max(self.channel_value_satoshis as i64 * 1000 - self.value_to_self_msat as i64 - - self.get_inbound_pending_htlc_stats().pending_htlcs_value_msat as i64 - - Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) as i64 * 1000, + - 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().pending_htlcs_value_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 ) } pub fn get_holder_counterparty_selected_channel_reserve_satoshis(&self) -> (u64, Option) { - (Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis), - self.counterparty_selected_channel_reserve_satoshis) + (self.holder_selected_channel_reserve_satoshis, self.counterparty_selected_channel_reserve_satoshis) } - // Get the fee cost of a commitment tx with a given number of HTLC outputs. + // 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. + // Note that num_htlcs should not include dust HTLCs. + #[inline] + fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize) -> u64 { + feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 } // Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the @@ -2120,12 +2220,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(); @@ -2198,12 +2298,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 { @@ -2249,14 +2349,13 @@ impl Channel { return Err(ChannelError::Close(format!("Remote side tried to send less than our minimum HTLC value. Lower limit: ({}). Actual: ({})", self.holder_htlc_minimum_msat, msg.amount_msat))); } - let inbound_stats = self.get_inbound_pending_htlc_stats(); - let outbound_stats = self.get_outbound_pending_htlc_stats(); + let inbound_stats = self.get_inbound_pending_htlc_stats(None); + let outbound_stats = self.get_outbound_pending_htlc_stats(None); if inbound_stats.pending_htlcs + 1 > OUR_MAX_HTLCS as u32 { return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS))); } - let holder_max_htlc_value_in_flight_msat = Channel::::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis); - if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat { - return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", holder_max_htlc_value_in_flight_msat))); + if inbound_stats.pending_htlcs_value_msat + msg.amount_msat > self.holder_max_htlc_value_in_flight_msat { + return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", self.holder_max_htlc_value_in_flight_msat))); } // Check holder_selected_channel_reserve_satoshis (we're getting paid, so they have to at least meet // the reserve_satoshis we told them to always have as direct payment so that they lose @@ -2279,7 +2378,7 @@ impl Channel { } } - let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; + let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats { let on_counterparty_tx_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + msg.amount_msat; if on_counterparty_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() { @@ -2289,7 +2388,7 @@ impl Channel { } } - let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; + let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; if msg.amount_msat / 1000 < exposure_dust_limit_success_sats { let on_holder_tx_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + msg.amount_msat; if on_holder_tx_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() { @@ -2317,9 +2416,7 @@ impl Channel { return Err(ChannelError::Close("Remote HTLC add would not leave enough to pay for fees".to_owned())); }; - let chan_reserve_msat = - Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000; - if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < chan_reserve_msat { + if pending_remote_value_msat - msg.amount_msat - remote_commit_tx_fee_msat < self.holder_selected_channel_reserve_satoshis * 1000 { return Err(ChannelError::Close("Remote HTLC add would put them under remote reserve value".to_owned())); } @@ -2334,7 +2431,7 @@ impl Channel { // sensitive to fee spikes. let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); let remote_fee_cost_incl_stuck_buffer_msat = 2 * self.next_remote_commit_tx_fee_msat(htlc_candidate, Some(())); - if pending_remote_value_msat - msg.amount_msat - chan_reserve_msat < remote_fee_cost_incl_stuck_buffer_msat { + if pending_remote_value_msat - msg.amount_msat - self.holder_selected_channel_reserve_satoshis * 1000 < remote_fee_cost_incl_stuck_buffer_msat { // Note that if the pending_forward_status is not updated here, then it's because we're already failing // the HTLC, i.e. its status is already set to failing. log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", log_bytes!(self.channel_id())); @@ -2453,36 +2550,32 @@ impl Channel { let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number).map_err(|e| (None, e))?; - let (num_htlcs, mut htlcs_cloned, commitment_tx, commitment_txid, feerate_per_kw) = { - let commitment_tx = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger); - let commitment_txid = { - let trusted_tx = commitment_tx.0.trust(); - let bitcoin_tx = trusted_tx.built_transaction(); - let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.channel_value_satoshis); - - log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in 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()) { - return Err((None, ChannelError::Close("Invalid commitment tx signature from peer".to_owned()))); - } - bitcoin_tx.txid - }; - let htlcs_cloned: Vec<_> = commitment_tx.3.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect(); - (commitment_tx.2, htlcs_cloned, commitment_tx.0, commitment_txid, commitment_tx.1) + let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, false, logger); + let commitment_txid = { + let trusted_tx = commitment_stats.tx.trust(); + let bitcoin_tx = trusted_tx.built_transaction(); + let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.channel_value_satoshis); + + log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in 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()) { + return Err((None, ChannelError::Close("Invalid commitment tx signature from peer".to_owned()))); + } + bitcoin_tx.txid }; + let mut htlcs_cloned: Vec<_> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect(); // If our counterparty updated the channel fee in this commitment transaction, check that // they can actually afford the new fee now. let update_fee = if let Some((_, update_state)) = self.pending_update_fee { update_state == FeeUpdateState::RemoteAnnounced } else { false }; - if update_fee { debug_assert!(!self.is_outbound()); } - let total_fee = feerate_per_kw as u64 * (COMMITMENT_TX_BASE_WEIGHT + (num_htlcs as u64) * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000; if update_fee { - let counterparty_reserve_we_require = Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis); - if self.channel_value_satoshis - self.value_to_self_msat / 1000 < total_fee + counterparty_reserve_we_require { + debug_assert!(!self.is_outbound()); + let counterparty_reserve_we_require_msat = self.holder_selected_channel_reserve_satoshis * 1000; + if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat { return Err((None, ChannelError::Close("Funding remote cannot afford proposed new fee".to_owned()))); } } @@ -2498,25 +2591,25 @@ 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 { - assert_eq!(total_fee, info.fee / 1000); + assert_eq!(commitment_stats.total_fee_sat, info.fee / 1000); } } } } - if msg.htlc_signatures.len() != num_htlcs { - return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), num_htlcs)))); + if msg.htlc_signatures.len() != commitment_stats.num_nondust_htlcs { + return Err((None, ChannelError::Close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_stats.num_nondust_htlcs)))); } // TODO: Sadly, we pass HTLCs twice to ChannelMonitor: once via the HolderCommitmentTransaction and once via the update let mut htlcs_and_sigs = Vec::with_capacity(htlcs_cloned.len()); 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, feerate_per_kw, - self.get_counterparty_selected_contest_delay().unwrap(), &htlc, + let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw, + 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()), @@ -2531,7 +2624,7 @@ impl Channel { } let holder_commitment_tx = HolderCommitmentTransaction::new( - commitment_tx, + commitment_stats.tx, msg.signature, msg.htlc_signatures.clone(), &self.get_holder_pubkeys().funding_pubkey, @@ -2667,7 +2760,7 @@ impl Channel { // to rebalance channels. match &htlc_update { &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => { - match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone()) { + match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), logger) { Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()), Err(e) => { match e { @@ -2726,12 +2819,7 @@ impl Channel { return Ok((None, htlcs_to_fail)); } let update_fee = if let Some(feerate) = self.holding_cell_update_fee.take() { - assert!(self.is_outbound()); - self.pending_update_fee = Some((feerate, FeeUpdateState::Outbound)); - Some(msgs::UpdateFee { - channel_id: self.channel_id, - feerate_per_kw: feerate as u32, - }) + self.send_update_fee(feerate, logger) } else { None }; @@ -3028,8 +3116,10 @@ impl Channel { /// Adds a pending update to this channel. See the doc for send_htlc for /// further details on the optionness of the return value. + /// If our balance is too low to cover the cost of the next commitment transaction at the + /// new feerate, the update is cancelled. /// You MUST call send_commitment prior to any other calls on this Channel - fn send_update_fee(&mut self, feerate_per_kw: u32) -> Option { + fn send_update_fee(&mut self, feerate_per_kw: u32, logger: &L) -> Option where L::Target: Logger { if !self.is_outbound() { panic!("Cannot send fee from inbound channel"); } @@ -3040,6 +3130,31 @@ impl Channel { panic!("Cannot update fee while peer is disconnected/we're awaiting a monitor update (ChannelManager should have caught this)"); } + // 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 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 + 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? + log_debug!(logger, "Cannot afford to send new feerate at {}", feerate_per_kw); + return None; + } + + // Note, we evaluate pending htlc "preemptive" trimmed-to-dust threshold at the proposed `feerate_per_kw`. + 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.get_max_dust_htlc_exposure_msat() { + log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw); + return None; + } + if counterparty_tx_dust_exposure > self.get_max_dust_htlc_exposure_msat() { + log_debug!(logger, "Cannot afford to send new feerate at {} without infringing max dust htlc exposure", feerate_per_kw); + return None; + } + if (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32 | ChannelState::MonitorUpdateFailed as u32)) != 0 { self.holding_cell_update_fee = Some(feerate_per_kw); return None; @@ -3055,7 +3170,7 @@ impl Channel { } pub fn send_update_fee_and_commit(&mut self, feerate_per_kw: u32, logger: &L) -> Result, ChannelError> where L::Target: Logger { - match self.send_update_fee(feerate_per_kw) { + match self.send_update_fee(feerate_per_kw, logger) { Some(update_fee) => { let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?; Ok(Some((update_fee, commitment_signed, monitor_update))) @@ -3219,7 +3334,7 @@ impl Channel { return Err(ChannelError::Close("Peer sent update_fee when we needed a channel_reestablish".to_owned())); } Channel::::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; - let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(); + let feerate_over_dust_buffer = msg.feerate_per_kw > self.get_dust_buffer_feerate(None); self.pending_update_fee = Some((msg.feerate_per_kw, FeeUpdateState::RemoteAnnounced)); self.update_time_counter += 1; @@ -3227,8 +3342,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(); - let outbound_stats = self.get_outbound_pending_htlc_stats(); + let inbound_stats = self.get_inbound_pending_htlc_stats(None); + let outbound_stats = self.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.get_max_dust_htlc_exposure_msat() { @@ -3900,7 +4015,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, - Channel::::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis) + self.holder_max_htlc_value_in_flight_msat ); } @@ -3929,7 +4044,7 @@ impl Channel { self.feerate_per_kw } - pub fn get_dust_buffer_feerate(&self) -> u32 { + pub fn get_dust_buffer_feerate(&self, outbound_feerate_update: Option) -> u32 { // When calculating our exposure to dust HTLCs, we assume that the channel feerate // may, at any point, increase by at least 10 sat/vB (i.e 2530 sat/kWU) or 25%, // whichever is higher. This ensures that we aren't suddenly exposed to significantly @@ -3941,6 +4056,9 @@ impl Channel { if let Some((feerate, _)) = self.pending_update_fee { feerate_per_kw = cmp::max(feerate_per_kw, feerate); } + if let Some(feerate) = outbound_feerate_update { + feerate_per_kw = cmp::max(feerate_per_kw, feerate); + } cmp::max(2530, feerate_per_kw * 1250 / 1000) } @@ -4117,7 +4235,7 @@ impl Channel { /// In the first case, we store the confirmation height and calculating the short channel id. /// In the second, we simply return an Err indicating we need to be force-closed now. pub fn transactions_confirmed(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData, logger: &L) - -> Result, msgs::ErrorMessage> where L::Target: Logger { + -> Result, ClosureReason> where L::Target: Logger { let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); for &(index_in_block, tx) in txdata.iter() { if let Some(funding_txo) = self.get_funding_txo() { @@ -4138,10 +4256,8 @@ impl Channel { panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); } self.update_time_counter += 1; - return Err(msgs::ErrorMessage { - channel_id: self.channel_id(), - data: "funding tx had wrong script/value or output index".to_owned() - }); + let err_reason = "funding tx had wrong script/value or output index"; + return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() }); } else { if self.is_outbound() { for input in tx.input.iter() { @@ -4172,10 +4288,7 @@ impl Channel { for inp in tx.input.iter() { if inp.previous_output == funding_txo.into_bitcoin_outpoint() { log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.channel_id())); - return Err(msgs::ErrorMessage { - channel_id: self.channel_id(), - data: "Commitment or closing transaction was confirmed on chain.".to_owned() - }); + return Err(ClosureReason::CommitmentTxConfirmed); } } } @@ -4195,9 +4308,12 @@ impl Channel { /// May return some HTLCs (and their payment_hash) which have timed out and should be failed /// back. pub fn best_block_updated(&mut self, height: u32, highest_header_time: u32, logger: &L) - -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> where L::Target: Logger { + -> Result<(Option, Vec<(HTLCSource, PaymentHash)>), ClosureReason> where L::Target: Logger { let mut timed_out_htlcs = Vec::new(); - let unforwarded_htlc_cltv_limit = height + HTLC_FAIL_BACK_BUFFER; + // This mirrors the check in ChannelManager::decode_update_add_htlc_onion, refusing to + // forward an HTLC when our counterparty should almost certainly just fail it for expiring + // ~now. + let unforwarded_htlc_cltv_limit = height + LATENCY_GRACE_PERIOD_BLOCKS; self.holding_cell_htlc_updates.retain(|htlc_update| { match htlc_update { &HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, ref cltv_expiry, .. } => { @@ -4233,11 +4349,17 @@ impl Channel { // 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 { - return Err(msgs::ErrorMessage { - channel_id: self.channel_id(), - data: format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth.unwrap(), funding_tx_confirmations), - }); + 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 }); } + } else if !self.is_outbound() && self.funding_tx_confirmed_in.is_none() && + height >= self.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS { + log_info!(logger, "Closing channel {} due to funding timeout", log_bytes!(self.channel_id)); + // If funding_tx_confirmed_in is unset, the channel must not be active + assert!(non_shutdown_state <= ChannelState::ChannelFunded as u32); + assert_eq!(non_shutdown_state & ChannelState::OurFundingLocked as u32, 0); + return Err(ClosureReason::FundingTimedOut); } Ok((None, timed_out_htlcs)) @@ -4246,7 +4368,7 @@ impl Channel { /// Indicates the funding transaction is no longer confirmed in the main chain. This may /// force-close the channel, but may also indicate a harmless reorganization of a block or two /// before the channel has reached funding_locked and we can just wait for more blocks. - pub fn funding_transaction_unconfirmed(&mut self, logger: &L) -> Result<(), msgs::ErrorMessage> where L::Target: Logger { + pub fn funding_transaction_unconfirmed(&mut self, logger: &L) -> Result<(), ClosureReason> where L::Target: Logger { if self.funding_tx_confirmation_height != 0 { // We handle the funding disconnection by calling best_block_updated with a height one // below where our funding was connected, implying a reorg back to conf_height - 1. @@ -4293,8 +4415,8 @@ impl Channel { funding_satoshis: self.channel_value_satoshis, push_msat: self.channel_value_satoshis * 1000 - self.value_to_self_msat, dust_limit_satoshis: self.holder_dust_limit_satoshis, - max_htlc_value_in_flight_msat: Channel::::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis), - channel_reserve_satoshis: Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis), + max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat, + channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis, htlc_minimum_msat: self.holder_htlc_minimum_msat, feerate_per_kw: self.feerate_per_kw as u32, to_self_delay: self.get_holder_selected_contest_delay(), @@ -4331,8 +4453,8 @@ impl Channel { msgs::AcceptChannel { temporary_channel_id: self.channel_id, dust_limit_satoshis: self.holder_dust_limit_satoshis, - max_htlc_value_in_flight_msat: Channel::::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis), - channel_reserve_satoshis: Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis), + max_htlc_value_in_flight_msat: self.holder_max_htlc_value_in_flight_msat, + channel_reserve_satoshis: self.holder_selected_channel_reserve_satoshis, htlc_minimum_msat: self.holder_htlc_minimum_msat, minimum_depth: self.minimum_depth.unwrap(), to_self_delay: self.get_holder_selected_contest_delay(), @@ -4353,7 +4475,7 @@ impl Channel { /// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created) fn get_outbound_funding_created_signature(&mut self, logger: &L) -> Result where L::Target: Logger { let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).0; + let counterparty_initial_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; Ok(self.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, &self.secp_ctx) .map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0) } @@ -4572,7 +4694,7 @@ impl Channel { /// You MUST call send_commitment prior to calling any other methods on this Channel! /// /// If an Err is returned, it's a ChannelError::Ignore! - pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result, ChannelError> { + pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result, ChannelError> where L::Target: Logger { if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned())); } @@ -4599,8 +4721,8 @@ impl Channel { return Err(ChannelError::Ignore("Cannot send an HTLC while disconnected from channel counterparty".to_owned())); } - let inbound_stats = self.get_inbound_pending_htlc_stats(); - let outbound_stats = self.get_outbound_pending_htlc_stats(); + let inbound_stats = self.get_inbound_pending_htlc_stats(None); + let outbound_stats = self.get_outbound_pending_htlc_stats(None); if outbound_stats.pending_htlcs + 1 > self.counterparty_max_accepted_htlcs as u32 { return Err(ChannelError::Ignore(format!("Cannot push more than their max accepted HTLCs ({})", self.counterparty_max_accepted_htlcs))); } @@ -4609,18 +4731,19 @@ impl Channel { return Err(ChannelError::Ignore(format!("Cannot send value that would put us over the max HTLC value in flight our peer will accept ({})", self.counterparty_max_htlc_value_in_flight_msat))); } + let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number)?; + let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger); if !self.is_outbound() { // Check that we won't violate the remote channel reserve by adding this HTLC. - let counterparty_balance_msat = self.channel_value_satoshis * 1000 - self.value_to_self_msat; - let holder_selected_chan_reserve_msat = Channel::::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) * 1000; let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered); let counterparty_commit_tx_fee_msat = self.next_remote_commit_tx_fee_msat(htlc_candidate, None); - if counterparty_balance_msat < holder_selected_chan_reserve_msat + counterparty_commit_tx_fee_msat { + let holder_selected_chan_reserve_msat = self.holder_selected_channel_reserve_satoshis * 1000; + if commitment_stats.remote_balance_msat < counterparty_commit_tx_fee_msat + holder_selected_chan_reserve_msat { return Err(ChannelError::Ignore("Cannot send value that would put counterparty balance under holder-announced channel reserve value".to_owned())); } } - let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; + let exposure_dust_limit_success_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis; if amount_msat / 1000 < exposure_dust_limit_success_sats { let on_counterparty_dust_htlc_exposure_msat = inbound_stats.on_counterparty_tx_dust_exposure_msat + outbound_stats.on_counterparty_tx_dust_exposure_msat + amount_msat; if on_counterparty_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() { @@ -4629,7 +4752,7 @@ impl Channel { } } - let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate() as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; + let exposure_dust_limit_timeout_sats = (self.get_dust_buffer_feerate(None) as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis; if amount_msat / 1000 < exposure_dust_limit_timeout_sats { let on_holder_dust_htlc_exposure_msat = inbound_stats.on_holder_tx_dust_exposure_msat + outbound_stats.on_holder_tx_dust_exposure_msat + amount_msat; if on_holder_dust_htlc_exposure_msat > self.get_max_dust_htlc_exposure_msat() { @@ -4638,9 +4761,9 @@ impl Channel { } } - let pending_value_to_self_msat = self.value_to_self_msat - outbound_stats.pending_htlcs_value_msat; - if pending_value_to_self_msat < amount_msat { - return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat))); + let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat; + if holder_balance_msat < amount_msat { + return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, holder_balance_msat))); } // `2 *` and extra HTLC are for the fee spike buffer. @@ -4648,14 +4771,14 @@ impl Channel { let htlc_candidate = HTLCCandidate::new(amount_msat, HTLCInitiator::LocalOffered); FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * self.next_local_commit_tx_fee_msat(htlc_candidate, Some(())) } else { 0 }; - if pending_value_to_self_msat - amount_msat < commit_tx_fee_msat { - return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", pending_value_to_self_msat, commit_tx_fee_msat))); + if holder_balance_msat - amount_msat < commit_tx_fee_msat { + return Err(ChannelError::Ignore(format!("Cannot send value that would not leave enough to pay for fees. Pending value to self: {}. local_commit_tx_fee {}", holder_balance_msat, commit_tx_fee_msat))); } // Check self.counterparty_selected_channel_reserve_satoshis (the amount we must keep as // reserve for the remote to have something to claim if we misbehave) let chan_reserve_msat = self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000; - if pending_value_to_self_msat - amount_msat - commit_tx_fee_msat < chan_reserve_msat { + if holder_balance_msat - amount_msat - commit_tx_fee_msat < chan_reserve_msat { return Err(ChannelError::Ignore(format!("Cannot send value that would put our balance under counterparty-announced channel reserve value ({})", chan_reserve_msat))); } @@ -4789,9 +4912,8 @@ impl Channel { /// when we shouldn't change HTLC/channel state. fn send_commitment_no_state_update(&self, logger: &L) -> Result<(msgs::CommitmentSigned, (Txid, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>)), ChannelError> where L::Target: Logger { let counterparty_keys = self.build_remote_transaction_keys()?; - let counterparty_commitment_tx = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger); - let feerate_per_kw = counterparty_commitment_tx.1; - let counterparty_commitment_txid = counterparty_commitment_tx.0.trust().txid(); + let commitment_stats = self.build_commitment_transaction(self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger); + let counterparty_commitment_txid = commitment_stats.tx.trust().txid(); let (signature, htlc_signatures); #[cfg(any(test, feature = "fuzztarget"))] @@ -4805,7 +4927,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(counterparty_commitment_tx.2); + let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs); assert_eq!(actual_fee, info.fee); } } @@ -4813,25 +4935,25 @@ impl Channel { } { - let mut htlcs = Vec::with_capacity(counterparty_commitment_tx.3.len()); - for &(ref htlc, _) in counterparty_commitment_tx.3.iter() { + let mut htlcs = Vec::with_capacity(commitment_stats.htlcs_included.len()); + for &(ref htlc, _) in commitment_stats.htlcs_included.iter() { htlcs.push(htlc); } - let res = self.holder_signer.sign_counterparty_commitment(&counterparty_commitment_tx.0, &self.secp_ctx) + let res = self.holder_signer.sign_counterparty_commitment(&commitment_stats.tx, &self.secp_ctx) .map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?; signature = res.0; htlc_signatures = res.1; log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {} in channel {}", - encode::serialize_hex(&counterparty_commitment_tx.0.trust().built_transaction().transaction), + encode::serialize_hex(&commitment_stats.tx.trust().built_transaction().transaction), &counterparty_commitment_txid, encode::serialize_hex(&self.get_funding_redeemscript()), log_bytes!(signature.serialize_compact()[..]), log_bytes!(self.channel_id())); 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, 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())); } @@ -4841,7 +4963,7 @@ impl Channel { channel_id: self.channel_id, signature, htlc_signatures, - }, (counterparty_commitment_txid, counterparty_commitment_tx.3))) + }, (counterparty_commitment_txid, commitment_stats.htlcs_included))) } /// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction @@ -4849,7 +4971,7 @@ impl Channel { /// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for /// more info. pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result, ChannelError> where L::Target: Logger { - match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet)? { + match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, logger)? { Some(update_add_htlc) => { let (commitment_signed, monitor_update) = self.send_commitment_no_status_check(logger)?; Ok(Some((update_add_htlc, commitment_signed, monitor_update))) @@ -5254,6 +5376,22 @@ impl Writeable for Channel { htlc.write(writer)?; } + // If the channel type is something other than only-static-remote-key, then we need to have + // older clients fail to deserialize this channel at all. If the type is + // only-static-remote-key, we simply consider it "default" and don't write the channel type + // out at all. + let chan_type = if self.channel_type != ChannelTypeFeatures::only_static_remote_key() { + Some(&self.channel_type) } else { None }; + + // The same logic applies for `holder_selected_channel_reserve_satoshis` and + // `holder_max_htlc_value_in_flight_msat` values other than the defaults. + let serialized_holder_selected_reserve = + if self.holder_selected_channel_reserve_satoshis != Self::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis) + { Some(self.holder_selected_channel_reserve_satoshis) } else { None }; + let serialized_holder_htlc_max_in_flight = + if self.holder_max_htlc_value_in_flight_msat != Self::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis) + { Some(self.holder_max_htlc_value_in_flight_msat) } else { None }; + write_tlv_fields!(writer, { (0, self.announcement_sigs, option), // minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a @@ -5263,12 +5401,15 @@ impl Writeable for Channel { // and new versions map the default values to None and allow the TLV entries here to // override that. (1, self.minimum_depth, option), + (2, chan_type, option), (3, self.counterparty_selected_channel_reserve_satoshis, option), + (4, serialized_holder_selected_reserve, option), (5, self.config, required), + (6, serialized_holder_htlc_max_in_flight, option), (7, self.shutdown_scriptpubkey, option), (9, self.target_closing_feerate_sats_per_kw, option), (11, self.monitor_pending_finalized_fulfills, vec_type), - (13, self.channel_type, required), + (13, self.channel_creation_height, required), }); Ok(()) @@ -5276,9 +5417,10 @@ impl Writeable for Channel { } const MAX_ALLOC_SIZE: usize = 64*1024; -impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel +impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel where K::Target: KeysInterface { - fn read(reader: &mut R, keys_source: &'a K) -> Result { + fn read(reader: &mut R, args: (&'a K, u32)) -> Result { + let (keys_source, serialized_height) = args; let ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); let user_id = Readable::read(reader)?; @@ -5503,18 +5645,24 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel let mut announcement_sigs = None; let mut target_closing_feerate_sats_per_kw = None; let mut monitor_pending_finalized_fulfills = Some(Vec::new()); + let mut holder_selected_channel_reserve_satoshis = Some(Self::get_holder_selected_channel_reserve_satoshis(channel_value_satoshis)); + let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis)); // Prior to supporting channel type negotiation, all of our channels were static_remotekey // only, so we default to that if none was written. let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key()); + let mut channel_creation_height = Some(serialized_height); read_tlv_fields!(reader, { (0, announcement_sigs, option), (1, minimum_depth, option), + (2, channel_type, option), (3, counterparty_selected_channel_reserve_satoshis, option), + (4, holder_selected_channel_reserve_satoshis, option), (5, config, option), // Note that if none is provided we will *not* overwrite the existing one. + (6, holder_max_htlc_value_in_flight_msat, option), (7, shutdown_scriptpubkey, option), (9, target_closing_feerate_sats_per_kw, option), (11, monitor_pending_finalized_fulfills, vec_type), - (13, channel_type, option), + (13, channel_creation_height, option), }); let chan_features = channel_type.as_ref().unwrap(); @@ -5524,6 +5672,11 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> 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()); @@ -5579,11 +5732,14 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel funding_tx_confirmed_in, funding_tx_confirmation_height, short_channel_id, + channel_creation_height: channel_creation_height.unwrap(), counterparty_dust_limit_satoshis, holder_dust_limit_satoshis, counterparty_max_htlc_value_in_flight_msat, + holder_max_htlc_value_in_flight_msat: holder_max_htlc_value_in_flight_msat.unwrap(), counterparty_selected_channel_reserve_satoshis, + holder_selected_channel_reserve_satoshis: holder_selected_channel_reserve_satoshis.unwrap(), counterparty_htlc_minimum_msat, holder_htlc_minimum_msat, counterparty_max_accepted_htlcs, @@ -5727,7 +5883,7 @@ mod tests { let secp_ctx = Secp256k1::new(); let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - match Channel::::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config) { + match Channel::::new_outbound(&&fee_estimator, &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0) { Err(APIError::IncompatibleShutdownScript { script }) => { assert_eq!(script.into_inner(), non_v0_segwit_shutdown_script.into_inner()); }, @@ -5749,7 +5905,7 @@ mod tests { let node_a_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - let node_a_chan = Channel::::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap(); + let node_a_chan = Channel::::new_outbound(&&fee_est, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap(); // Now change the fee so we can check that the fee in the open_channel message is the // same as the old fee. @@ -5767,6 +5923,7 @@ mod tests { let seed = [42; 32]; let network = Network::Testnet; let keys_provider = test_utils::TestKeysInterface::new(&seed, network); + let logger = test_utils::TestLogger::new(); // Go through the flow of opening a channel between two nodes, making sure // they have different dust limits. @@ -5774,13 +5931,13 @@ mod tests { // Create Node A's channel pointing to Node B's pubkey let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap(); // Create Node B's channel by receiving Node A's open_channel message // Make sure A's dust limit is as we expect. let open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash()); let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); - let node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config).unwrap(); + let node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap(); // Node B --> Node A: accept channel, explicitly setting B's dust limit. let mut accept_channel_msg = node_b_chan.get_accept_channel(); @@ -5818,13 +5975,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); @@ -5844,10 +6001,10 @@ mod tests { let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - let mut chan = Channel::::new_outbound(&&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap(); + 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. @@ -5893,12 +6050,12 @@ mod tests { // Create Node A's channel pointing to Node B's pubkey let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap(); // Create Node B's channel by receiving Node A's open_channel message let open_channel_msg = node_a_chan.get_open_channel(chain_hash); let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); - let mut node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config).unwrap(); + let mut node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger).unwrap(); // Node B --> Node A: accept channel let accept_channel_msg = node_b_chan.get_accept_channel(); @@ -5955,7 +6112,7 @@ mod tests { // Create a channel. let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let config = UserConfig::default(); - let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0).unwrap(); assert!(node_a_chan.counterparty_forwarding_info.is_none()); assert_eq!(node_a_chan.holder_htlc_minimum_msat, 1); // the default assert!(node_a_chan.counterparty_forwarding_info().is_none()); @@ -6019,7 +6176,7 @@ mod tests { let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let mut config = UserConfig::default(); config.channel_options.announced_channel = false; - let mut chan = Channel::::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config).unwrap(); // Nothing uses their network key in this test + let mut chan = Channel::::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0).unwrap(); // Nothing uses their network key in this test chan.holder_dust_limit_satoshis = 546; chan.counterparty_selected_channel_reserve_satoshis = Some(0); // Filled in in accept_channel @@ -6063,12 +6220,12 @@ mod tests { $( { $htlc_idx: expr, $counterparty_htlc_sig_hex: expr, $htlc_sig_hex: expr, $htlc_tx_hex: expr } ), * } ) => { { let (commitment_tx, htlcs): (_, Vec) = { - let mut res = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger); + let mut commitment_stats = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, &logger); - let htlcs = res.3.drain(..) + let htlcs = commitment_stats.htlcs_included.drain(..) .filter_map(|(htlc, _)| if htlc.transaction_output_index.is_some() { Some(htlc) } else { None }) .collect(); - (res.0, htlcs) + (commitment_stats.tx, htlcs) }; let trusted_tx = commitment_tx.trust(); let unsigned_tx = trusted_tx.built_transaction(); @@ -6109,10 +6266,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();