X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannel.rs;h=6da5de04365ee4b1cc20f7501c62605a91d84643;hb=602cf5c12bb4ff7ea28291e4d6a7be770b8863d8;hp=f50865dc4af22044d9eaabedf560c1da845d98b4;hpb=5421e1a6e712ae3d04569562fd036e29908188d7;p=rust-lightning diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f50865dc..6da5de04 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -31,7 +31,7 @@ use ln::channelmanager::{CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSour use ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction}; use ln::chan_utils; use chain::BestBlock; -use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; +use chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator}; use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS}; use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::{Sign, KeysInterface}; @@ -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, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits}; +use util::config::{UserConfig, ChannelConfig, LegacyChannelConfig, ChannelHandshakeConfig, ChannelHandshakeLimits}; use util::scid_utils::scid_from_parts; use io; @@ -482,6 +482,16 @@ pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2; /// transaction (not counting the value of the HTLCs themselves). pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4; +/// When a [`Channel`] has its [`ChannelConfig`] updated, its existing one is stashed for up to this +/// number of ticks to allow forwarding HTLCs by nodes that have yet to receive the new +/// ChannelUpdate prompted by the config update. This value was determined as follows: +/// +/// * The expected interval between ticks (1 minute). +/// * The average convergence delay of updates across the network, i.e., ~300 seconds on average +/// for a node to see an update as seen on ``. +/// * `EXPIRE_PREV_CONFIG_TICKS` = convergence_delay / tick_interval +pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5; + // 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 @@ -490,11 +500,13 @@ pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4; // Holder designates channel data owned for the benefice of the user client. // Counterparty designates channel data owned by the another channel participant entity. pub(super) struct Channel { - #[cfg(any(test, feature = "_test_utils"))] - pub(crate) config: LegacyChannelConfig, - #[cfg(not(any(test, feature = "_test_utils")))] config: LegacyChannelConfig, + // Track the previous `ChannelConfig` so that we can continue forwarding HTLCs that were + // constructed using it. The second element in the tuple corresponds to the number of ticks that + // have elapsed since the update occurred. + prev_config: Option<(ChannelConfig, usize)>, + inbound_handshake_limits_override: Option, user_id: u64, @@ -790,7 +802,6 @@ pub(super) enum ChannelError { Ignore(String), Warn(String), Close(String), - CloseDelayBroadcast(String), } impl fmt::Debug for ChannelError { @@ -799,7 +810,6 @@ impl fmt::Debug for ChannelError { &ChannelError::Ignore(ref e) => write!(f, "Ignore : {}", e), &ChannelError::Warn(ref e) => write!(f, "Warn : {}", e), &ChannelError::Close(ref e) => write!(f, "Close : {}", e), - &ChannelError::CloseDelayBroadcast(ref e) => write!(f, "CloseDelayBroadcast : {}", e) } } } @@ -855,7 +865,7 @@ impl Channel { // available. If it's private, we first try `scid_privacy` as it provides better privacy // with no other changes, and fall back to `only_static_remotekey` let mut ret = ChannelTypeFeatures::only_static_remote_key(); - if !config.own_channel_config.announced_channel && config.own_channel_config.negotiate_scid_privacy { + if !config.channel_handshake_config.announced_channel && config.channel_handshake_config.negotiate_scid_privacy { ret.set_scid_privacy_required(); } ret @@ -876,7 +886,7 @@ impl Channel { // Constructors: pub fn new_outbound( - fee_estimator: &F, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, + fee_estimator: &LowerBoundedFeeEstimator, 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, outbound_scid_alias: u64 ) -> Result, APIError> @@ -885,7 +895,7 @@ impl Channel { { let opt_anchors = false; // TODO - should be based on features - let holder_selected_contest_delay = config.own_channel_config.our_to_self_delay; + let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay; let holder_signer = keys_provider.get_channel_signer(false, channel_value_satoshis); let pubkeys = holder_signer.pubkeys().clone(); @@ -907,7 +917,7 @@ impl Channel { return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) }); } - let feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors); @@ -918,7 +928,7 @@ impl Channel { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&keys_provider.get_secure_random_bytes()); - let shutdown_scriptpubkey = if config.own_channel_config.commit_upfront_shutdown_pubkey { + let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { Some(keys_provider.get_shutdown_scriptpubkey()) } else { None }; @@ -932,12 +942,14 @@ impl Channel { user_id, config: LegacyChannelConfig { - mutable: config.channel_options.clone(), - announced_channel: config.own_channel_config.announced_channel, - commit_upfront_shutdown_pubkey: config.own_channel_config.commit_upfront_shutdown_pubkey, + options: config.channel_config.clone(), + announced_channel: config.channel_handshake_config.announced_channel, + commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey, }, - inbound_handshake_limits_override: Some(config.peer_channel_config_limits.clone()), + prev_config: None, + + inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()), channel_id: keys_provider.get_secure_random_bytes(), channel_state: ChannelState::OurInitSent as u32, @@ -994,11 +1006,11 @@ 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, &config.own_channel_config), + holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config), counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel holder_selected_channel_reserve_satoshis, counterparty_htlc_minimum_msat: 0, - holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat }, + holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat }, counterparty_max_accepted_htlcs: 0, minimum_depth: None, // Filled in in accept_channel @@ -1006,7 +1018,7 @@ impl Channel { channel_transaction_parameters: ChannelTransactionParameters { holder_pubkeys: pubkeys, - holder_selected_contest_delay: config.own_channel_config.our_to_self_delay, + holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, is_outbound_from_holder: true, counterparty_parameters: None, funding_outpoint: None, @@ -1044,7 +1056,7 @@ impl Channel { }) } - fn check_remote_fee(fee_estimator: &F, feerate_per_kw: u32) -> Result<(), ChannelError> + fn check_remote_fee(fee_estimator: &LowerBoundedFeeEstimator, feerate_per_kw: u32) -> Result<(), ChannelError> where F::Target: FeeEstimator { // We only bound the fee updates on the upper side to prevent completely absurd feerates, @@ -1052,11 +1064,11 @@ impl Channel { // We generally don't care too much if they set the feerate to something very high, but it // could result in the channel being useless due to everything being dust. let upper_limit = cmp::max(250 * 25, - fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 10); + fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::HighPriority) as u64 * 10); if feerate_per_kw as u64 > upper_limit { return Err(ChannelError::Close(format!("Peer's feerate much too high. Actual: {}. Our expected upper limit: {}", feerate_per_kw, upper_limit))); } - let lower_limit = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background); + let lower_limit = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background); // 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 @@ -1070,7 +1082,7 @@ 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, + fee_estimator: &LowerBoundedFeeEstimator, keys_provider: &K, counterparty_node_id: PublicKey, their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u64, config: &UserConfig, current_chain_height: u32, logger: &L, outbound_scid_alias: u64 ) -> Result, ChannelError> @@ -1124,13 +1136,13 @@ impl Channel { htlc_basepoint: msg.htlc_basepoint }; - if config.own_channel_config.our_to_self_delay < BREAKDOWN_TIMEOUT { - return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.own_channel_config.our_to_self_delay, BREAKDOWN_TIMEOUT))); + if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT { + return Err(ChannelError::Close(format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks. It must be greater than {}", config.channel_handshake_config.our_to_self_delay, BREAKDOWN_TIMEOUT))); } // Check sanity of message fields: - 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 > config.channel_handshake_limits.max_funding_satoshis { + return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.channel_handshake_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))); @@ -1150,7 +1162,7 @@ impl Channel { } Channel::::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; - let max_counterparty_selected_contest_delay = u16::min(config.peer_channel_config_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT); + let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT); if msg.to_self_delay > max_counterparty_selected_contest_delay { return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_counterparty_selected_contest_delay, msg.to_self_delay))); } @@ -1162,20 +1174,20 @@ impl Channel { } // Now check against optional parameters as set by config... - if msg.funding_satoshis < config.peer_channel_config_limits.min_funding_satoshis { - return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.peer_channel_config_limits.min_funding_satoshis))); + if msg.funding_satoshis < config.channel_handshake_limits.min_funding_satoshis { + return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.channel_handshake_limits.min_funding_satoshis))); } - if msg.htlc_minimum_msat > config.peer_channel_config_limits.max_htlc_minimum_msat { - return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, config.peer_channel_config_limits.max_htlc_minimum_msat))); + if msg.htlc_minimum_msat > config.channel_handshake_limits.max_htlc_minimum_msat { + return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, config.channel_handshake_limits.max_htlc_minimum_msat))); } - if msg.max_htlc_value_in_flight_msat < config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat { - return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.peer_channel_config_limits.min_max_htlc_value_in_flight_msat))); + if msg.max_htlc_value_in_flight_msat < config.channel_handshake_limits.min_max_htlc_value_in_flight_msat { + return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.channel_handshake_limits.min_max_htlc_value_in_flight_msat))); } - if msg.channel_reserve_satoshis > config.peer_channel_config_limits.max_channel_reserve_satoshis { - return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.peer_channel_config_limits.max_channel_reserve_satoshis))); + if msg.channel_reserve_satoshis > config.channel_handshake_limits.max_channel_reserve_satoshis { + return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.channel_handshake_limits.max_channel_reserve_satoshis))); } - if msg.max_accepted_htlcs < config.peer_channel_config_limits.min_max_accepted_htlcs { - return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.peer_channel_config_limits.min_max_accepted_htlcs))); + if msg.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs { + return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs))); } if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS { return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS))); @@ -1186,8 +1198,8 @@ impl Channel { // Convert things into internal flags and prep our state: - if config.peer_channel_config_limits.force_announced_channel_preference { - if config.own_channel_config.announced_channel != announced_channel { + if config.channel_handshake_limits.force_announced_channel_preference { + if config.channel_handshake_config.announced_channel != announced_channel { return Err(ChannelError::Close("Peer tried to open channel but their announcement preference is different from ours".to_owned())); } } @@ -1242,7 +1254,7 @@ impl Channel { } } else { None }; - let shutdown_scriptpubkey = if config.own_channel_config.commit_upfront_shutdown_pubkey { + let shutdown_scriptpubkey = if config.channel_handshake_config.commit_upfront_shutdown_pubkey { Some(keys_provider.get_shutdown_scriptpubkey()) } else { None }; @@ -1259,11 +1271,13 @@ impl Channel { user_id, config: LegacyChannelConfig { - mutable: config.channel_options.clone(), + options: config.channel_config.clone(), announced_channel, - commit_upfront_shutdown_pubkey: config.own_channel_config.commit_upfront_shutdown_pubkey, + commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey, }, + prev_config: None, + inbound_handshake_limits_override: None, channel_id: msg.temporary_channel_id, @@ -1321,19 +1335,19 @@ 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, &config.own_channel_config), + holder_max_htlc_value_in_flight_msat: Self::get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.channel_handshake_config), 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 }, + holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat }, counterparty_max_accepted_htlcs: msg.max_accepted_htlcs, - minimum_depth: Some(cmp::max(config.own_channel_config.minimum_depth, 1)), + minimum_depth: Some(cmp::max(config.channel_handshake_config.minimum_depth, 1)), counterparty_forwarding_info: None, channel_transaction_parameters: ChannelTransactionParameters { holder_pubkeys: pubkeys, - holder_selected_contest_delay: config.own_channel_config.our_to_self_delay, + holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, is_outbound_from_holder: false, counterparty_parameters: Some(CounterpartyChannelTransactionParameters { selected_contest_delay: msg.to_self_delay, @@ -2195,7 +2209,7 @@ impl Channel { &self.channel_transaction_parameters, funding_redeemscript.clone(), self.channel_value_satoshis, obscure_factor, - holder_commitment_tx, best_block); + holder_commitment_tx, best_block, self.counterparty_node_id); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_commitment_txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -2272,7 +2286,7 @@ impl Channel { &self.channel_transaction_parameters, funding_redeemscript.clone(), self.channel_value_satoshis, obscure_factor, - holder_commitment_tx, best_block); + holder_commitment_tx, best_block, self.counterparty_node_id); channel_monitor.provide_latest_counterparty_commitment_tx(counterparty_initial_bitcoin_tx.txid, Vec::new(), self.cur_counterparty_commitment_transaction_number, self.counterparty_cur_commitment_point.unwrap(), logger); @@ -3673,7 +3687,7 @@ impl Channel { } } - pub fn update_fee(&mut self, fee_estimator: &F, msg: &msgs::UpdateFee) -> Result<(), ChannelError> + pub fn update_fee(&mut self, fee_estimator: &LowerBoundedFeeEstimator, msg: &msgs::UpdateFee) -> Result<(), ChannelError> where F::Target: FeeEstimator { if self.is_outbound() { @@ -3783,6 +3797,11 @@ impl Channel { /// May panic if some calls other than message-handling calls (which will all Err immediately) /// have been called between remove_uncommitted_htlcs_and_mark_paused and this call. + /// + /// Some links printed in log lines are included here to check them during build (when run with + /// `cargo doc --document-private-items`): + /// [`super::channelmanager::ChannelManager::force_close_without_broadcasting_txn`] and + /// [`super::channelmanager::ChannelManager::force_close_all_channels_without_broadcasting_txn`]. pub fn channel_reestablish(&mut self, msg: &msgs::ChannelReestablish, logger: &L, node_pk: PublicKey, genesis_block_hash: BlockHash, best_block: &BestBlock) -> Result where L::Target: Logger { @@ -3808,9 +3827,20 @@ impl Channel { return Err(ChannelError::Close("Peer sent a garbage channel_reestablish with secret key not matching the commitment height provided".to_owned())); } if msg.next_remote_commitment_number > INITIAL_COMMITMENT_NUMBER - self.cur_holder_commitment_transaction_number { - return Err(ChannelError::CloseDelayBroadcast( - "We have fallen behind - we have received proof that if we broadcast remote is going to claim our funds - we can't do any automated broadcasting".to_owned() - )); + macro_rules! log_and_panic { + ($err_msg: expr) => { + log_error!(logger, $err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); + panic!($err_msg, log_bytes!(self.channel_id), log_pubkey!(self.counterparty_node_id)); + } + } + log_and_panic!("We have fallen behind - we have received proof that if we broadcast our counterparty is going to claim all our funds.\n\ + This implies you have restarted with lost ChannelMonitor and ChannelManager state, the first of which is a violation of the LDK chain::Watch requirements.\n\ + More specifically, this means you have a bug in your implementation that can cause loss of funds, or you are running with an old backup, which is unsafe.\n\ + If you have restored from an old backup and wish to force-close channels and return to operation, you should start up, call\n\ + ChannelManager::force_close_without_broadcasting_txn on channel {} with counterparty {} or\n\ + ChannelManager::force_close_all_channels_without_broadcasting_txn, then reconnect to peer(s).\n\ + Note that due to a long-standing bug in lnd you may have to reach out to peers running lnd-based nodes to ask them to manually force-close channels\n\ + See https://github.com/lightningdevkit/rust-lightning/issues/1565 for more info."); } }, OptionalField::Absent => {} @@ -3917,7 +3947,7 @@ impl Channel { // now! match self.free_holding_cell_htlcs(logger) { Err(ChannelError::Close(msg)) => Err(ChannelError::Close(msg)), - Err(ChannelError::Warn(_)) | Err(ChannelError::Ignore(_)) | Err(ChannelError::CloseDelayBroadcast(_)) => + Err(ChannelError::Warn(_)) | Err(ChannelError::Ignore(_)) => panic!("Got non-channel-failing result from free_holding_cell_htlcs"), Ok((Some((commitment_update, monitor_update)), holding_cell_failed_htlcs)) => { Ok(ReestablishResponses { @@ -3983,7 +4013,8 @@ impl Channel { /// Calculates and returns our minimum and maximum closing transaction fee amounts, in whole /// satoshis. The amounts remain consistent unless a peer disconnects/reconnects or we restart, /// at which point they will be recalculated. - fn calculate_closing_fee_limits(&mut self, fee_estimator: &F) -> (u64, u64) + fn calculate_closing_fee_limits(&mut self, fee_estimator: &LowerBoundedFeeEstimator) + -> (u64, u64) where F::Target: FeeEstimator { if let Some((min, max)) = self.closing_fee_limits { return (min, max); } @@ -3991,8 +4022,8 @@ impl Channel { // Propose a range from our current Background feerate to our Normal feerate plus our // force_close_avoidance_max_fee_satoshis. // If we fail to come to consensus, we'll have to force-close. - let mut proposed_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background); - let normal_feerate = fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let mut proposed_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Background); + let normal_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); let mut proposed_max_feerate = if self.is_outbound() { normal_feerate } else { u32::max_value() }; // The spec requires that (when the channel does not have anchors) we only send absolute @@ -4020,7 +4051,7 @@ impl Channel { // We always add force_close_avoidance_max_fee_satoshis to our normal // feerate-calculated fee, but allow the max to be overridden if we're using a // target feerate-calculated fee. - cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.mutable.force_close_avoidance_max_fee_satoshis, + cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.config.options.force_close_avoidance_max_fee_satoshis, proposed_max_feerate as u64 * tx_weight / 1000) } else { self.channel_value_satoshis - (self.value_to_self_msat + 999) / 1000 @@ -4057,7 +4088,8 @@ impl Channel { Ok(()) } - pub fn maybe_propose_closing_signed(&mut self, fee_estimator: &F, logger: &L) + pub fn maybe_propose_closing_signed( + &mut self, fee_estimator: &LowerBoundedFeeEstimator, logger: &L) -> Result<(Option, Option), ChannelError> where F::Target: FeeEstimator, L::Target: Logger { @@ -4211,7 +4243,9 @@ impl Channel { tx } - pub fn closing_signed(&mut self, fee_estimator: &F, msg: &msgs::ClosingSigned) -> Result<(Option, Option), ChannelError> + pub fn closing_signed( + &mut self, fee_estimator: &LowerBoundedFeeEstimator, msg: &msgs::ClosingSigned) + -> Result<(Option, Option), ChannelError> where F::Target: FeeEstimator { if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != BOTH_SIDES_SHUTDOWN_MASK { @@ -4480,15 +4514,93 @@ impl Channel { } pub fn get_fee_proportional_millionths(&self) -> u32 { - self.config.mutable.forwarding_fee_proportional_millionths + self.config.options.forwarding_fee_proportional_millionths } pub fn get_cltv_expiry_delta(&self) -> u16 { - cmp::max(self.config.mutable.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA) + cmp::max(self.config.options.cltv_expiry_delta, MIN_CLTV_EXPIRY_DELTA) } pub fn get_max_dust_htlc_exposure_msat(&self) -> u64 { - self.config.mutable.max_dust_htlc_exposure_msat + self.config.options.max_dust_htlc_exposure_msat + } + + /// Returns the previous [`ChannelConfig`] applied to this channel, if any. + pub fn prev_config(&self) -> Option { + self.prev_config.map(|prev_config| prev_config.0) + } + + /// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once + /// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will + /// no longer be considered when forwarding HTLCs. + pub fn maybe_expire_prev_config(&mut self) { + if self.prev_config.is_none() { + return; + } + let prev_config = self.prev_config.as_mut().unwrap(); + prev_config.1 += 1; + if prev_config.1 == EXPIRE_PREV_CONFIG_TICKS { + self.prev_config = None; + } + } + + /// Returns the current [`ChannelConfig`] applied to the channel. + pub fn config(&self) -> ChannelConfig { + self.config.options + } + + /// Updates the channel's config. A bool is returned indicating whether the config update + /// applied resulted in a new ChannelUpdate message. + pub fn update_config(&mut self, config: &ChannelConfig) -> bool { + let did_channel_update = + self.config.options.forwarding_fee_proportional_millionths != config.forwarding_fee_proportional_millionths || + self.config.options.forwarding_fee_base_msat != config.forwarding_fee_base_msat || + self.config.options.cltv_expiry_delta != config.cltv_expiry_delta; + if did_channel_update { + self.prev_config = Some((self.config.options, 0)); + // Update the counter, which backs the ChannelUpdate timestamp, to allow the relay + // policy change to propagate throughout the network. + self.update_time_counter += 1; + } + self.config.options = *config; + did_channel_update + } + + fn internal_htlc_satisfies_config( + &self, htlc: &msgs::UpdateAddHTLC, amt_to_forward: u64, outgoing_cltv_value: u32, config: &ChannelConfig, + ) -> Result<(), (&'static str, u16)> { + let fee = amt_to_forward.checked_mul(config.forwarding_fee_proportional_millionths as u64) + .and_then(|prop_fee| (prop_fee / 1000000).checked_add(config.forwarding_fee_base_msat as u64)); + if fee.is_none() || htlc.amount_msat < fee.unwrap() || + (htlc.amount_msat - fee.unwrap()) < amt_to_forward { + return Err(( + "Prior hop has deviated from specified fees parameters or origin node has obsolete ones", + 0x1000 | 12, // fee_insufficient + )); + } + if (htlc.cltv_expiry as u64) < outgoing_cltv_value as u64 + config.cltv_expiry_delta as u64 { + return Err(( + "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", + 0x1000 | 13, // incorrect_cltv_expiry + )); + } + Ok(()) + } + + /// Determines whether the parameters of an incoming HTLC to be forwarded satisfy the channel's + /// [`ChannelConfig`]. This first looks at the channel's current [`ChannelConfig`], and if + /// unsuccessful, falls back to the previous one if one exists. + pub fn htlc_satisfies_config( + &self, htlc: &msgs::UpdateAddHTLC, amt_to_forward: u64, outgoing_cltv_value: u32, + ) -> Result<(), (&'static str, u16)> { + self.internal_htlc_satisfies_config(&htlc, amt_to_forward, outgoing_cltv_value, &self.config()) + .or_else(|err| { + if let Some(prev_config) = self.prev_config() { + self.internal_htlc_satisfies_config(htlc, amt_to_forward, outgoing_cltv_value, &prev_config) + } else { + Err(err) + } + }) } pub fn get_feerate(&self) -> u32 { @@ -4575,7 +4687,7 @@ impl Channel { /// Gets the fee we'd want to charge for adding an HTLC output to this Channel /// Allowed in any state (including after shutdown) pub fn get_outbound_forwarding_fee_base_msat(&self) -> u32 { - self.config.mutable.forwarding_fee_base_msat + self.config.options.forwarding_fee_base_msat } /// Returns true if we've ever received a message from the remote end for this Channel @@ -4828,8 +4940,9 @@ impl Channel { // the funding transaction is at least still in the mempool of most nodes). // // Note that ideally we wouldn't force-close if we see *any* reorg on a 1-conf or - // 0-conf channel, but not doing so may lead to the `ChannelManager::short_to_id` map - // being inconsistent, so we currently have to. + // 0-conf channel, but not doing so may lead to the + // `ChannelManager::short_to_chan_info` 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); @@ -5652,7 +5765,7 @@ impl Channel { /// those explicitly stated to be allowed after shutdown completes, eg some simple getters). /// Also returns the list of payment_hashes for channels which we can safely fail backwards /// immediately (others we will have to allow to time out). - pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash)>) { + pub fn force_shutdown(&mut self, should_broadcast: bool) -> (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>) { // Note that we MUST only generate a monitor update that indicates force-closure - we're // called during initialization prior to the chain_monitor in the encompassing ChannelManager // being fully configured in some cases. Thus, its likely any monitor events we generate will @@ -5662,10 +5775,11 @@ impl Channel { // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and // return them to fail the payment. let mut dropped_outbound_htlcs = Vec::with_capacity(self.holding_cell_htlc_updates.len()); + let counterparty_node_id = self.get_counterparty_node_id(); for htlc_update in self.holding_cell_htlc_updates.drain(..) { match htlc_update { HTLCUpdateAwaitingACK::AddHTLC { source, payment_hash, .. } => { - dropped_outbound_htlcs.push((source, payment_hash)); + dropped_outbound_htlcs.push((source, payment_hash, counterparty_node_id, self.channel_id)); }, _ => {} } @@ -5996,7 +6110,7 @@ impl Writeable for Channel { 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; + let mut old_max_in_flight_percent_config = UserConfig::default().channel_handshake_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, &old_max_in_flight_percent_config) @@ -6042,8 +6156,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel let mut config = Some(LegacyChannelConfig::default()); if ver == 1 { // Read the old serialization of the ChannelConfig from version 0.0.98. - config.as_mut().unwrap().mutable.forwarding_fee_proportional_millionths = Readable::read(reader)?; - config.as_mut().unwrap().mutable.cltv_expiry_delta = Readable::read(reader)?; + config.as_mut().unwrap().options.forwarding_fee_proportional_millionths = Readable::read(reader)?; + config.as_mut().unwrap().options.cltv_expiry_delta = Readable::read(reader)?; config.as_mut().unwrap().announced_channel = Readable::read(reader)?; config.as_mut().unwrap().commit_upfront_shutdown_pubkey = Readable::read(reader)?; } else { @@ -6269,7 +6383,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, &UserConfig::default().own_channel_config)); + let mut holder_max_htlc_value_in_flight_msat = Some(Self::get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &UserConfig::default().channel_handshake_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()); @@ -6339,6 +6453,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel config: config.unwrap(), + prev_config: None, + // Note that we don't care about serializing handshake limits as we only ever serialize // channel data after the handshake has completed. inbound_handshake_limits_override: None, @@ -6457,12 +6573,12 @@ mod tests { use ln::channel::{Channel, InboundHTLCOutput, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator}; use ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS}; use ln::features::{InitFeatures, ChannelTypeFeatures}; - use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate}; + use ln::msgs::{ChannelUpdate, DataLossProtect, DecodeError, OptionalField, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use ln::script::ShutdownScript; use ln::chan_utils; use ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight}; use chain::BestBlock; - use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; + use chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget}; use chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface}; use chain::transaction::OutPoint; use util::config::UserConfig; @@ -6501,7 +6617,9 @@ mod tests { fn test_no_fee_check_overflow() { // Previously, calling `check_remote_fee` with a fee of 0xffffffff would overflow in // arithmetic, causing a panic with debug assertions enabled. - assert!(Channel::::check_remote_fee(&&TestFeeEstimator { fee_est: 42 }, u32::max_value()).is_err()); + let fee_est = TestFeeEstimator { fee_est: 42 }; + let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_est); + assert!(Channel::::check_remote_fee(&bounded_fee_estimator, u32::max_value()).is_err()); } struct Keys { @@ -6551,11 +6669,10 @@ mod tests { returns: non_v0_segwit_shutdown_script.clone(), }); - let fee_estimator = TestFeeEstimator { fee_est: 253 }; 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, 0, 42) { + match Channel::::new_outbound(&LowerBoundedFeeEstimator::new(&TestFeeEstimator { fee_est: 253 }), &&keys_provider, node_id, &features, 10000000, 100000, 42, &config, 0, 42) { Err(APIError::IncompatibleShutdownScript { script }) => { assert_eq!(script.into_inner(), non_v0_segwit_shutdown_script.into_inner()); }, @@ -6570,6 +6687,7 @@ mod tests { fn test_open_channel_msg_fee() { let original_fee = 253; let mut fee_est = TestFeeEstimator{fee_est: original_fee }; + let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&fee_est); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; @@ -6577,7 +6695,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, 0, 42).unwrap(); + let node_a_chan = Channel::::new_outbound(&bounded_fee_estimator, &&keys_provider, node_a_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap(); // Now change the fee so we can check that the fee in the open_channel message is the // same as the old fee. @@ -6590,7 +6708,7 @@ mod tests { fn test_holder_vs_counterparty_dust_limit() { // Test that when calculating the local and remote commitment transaction fees, the correct // dust limits are used. - let feeest = TestFeeEstimator{fee_est: 15000}; + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; @@ -6603,18 +6721,18 @@ 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, 0, 42).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).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 mut node_b_chan = Channel::::new_from_req(&&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42).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, 42).unwrap(); // Node B --> Node A: accept channel, explicitly setting B's dust limit. let mut accept_channel_msg = node_b_chan.accept_inbound_channel(0); accept_channel_msg.dust_limit_satoshis = 546; - node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap(); + node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap(); node_a_chan.holder_dust_limit_satoshis = 1560; // Put some inbound and outbound HTLCs in A's channel. @@ -6665,7 +6783,7 @@ mod tests { // calculate the real dust limits for HTLCs (i.e. the dust limit given by the counterparty // *plus* the fees paid for the HTLC) they don't swap `HTLC_SUCCESS_TX_WEIGHT` for // `HTLC_TIMEOUT_TX_WEIGHT`, and vice versa. - let fee_est = TestFeeEstimator{fee_est: 253 }; + let fee_est = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 253 }); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; @@ -6673,7 +6791,7 @@ 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, 0, 42).unwrap(); + let mut chan = Channel::::new_outbound(&fee_est, &&keys_provider, node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap(); let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0, chan.opt_anchors()); let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1, chan.opt_anchors()); @@ -6708,7 +6826,7 @@ mod tests { #[test] fn channel_reestablish_no_updates() { - let feeest = TestFeeEstimator{fee_est: 15000}; + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); let logger = test_utils::TestLogger::new(); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; @@ -6722,16 +6840,16 @@ 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, 0, 42).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).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, 0, &&logger, 42).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, 42).unwrap(); // Node B --> Node A: accept channel let accept_channel_msg = node_b_chan.accept_inbound_channel(0); - node_a_chan.accept_channel(&accept_channel_msg, &config.peer_channel_config_limits, &InitFeatures::known()).unwrap(); + node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &InitFeatures::known()).unwrap(); // Node A --> Node B: funding created let output_script = node_a_chan.get_funding_redeemscript(); @@ -6774,7 +6892,7 @@ mod tests { #[test] fn test_configured_holder_max_htlc_value_in_flight() { - let feeest = TestFeeEstimator{fee_est: 15000}; + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); let logger = test_utils::TestLogger::new(); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; @@ -6784,23 +6902,23 @@ mod tests { 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; + config_2_percent.channel_handshake_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; + config_99_percent.channel_handshake_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; + config_0_percent.channel_handshake_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; + config_101_percent.channel_handshake_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 = 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 = 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); @@ -6809,45 +6927,45 @@ mod tests { // 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 = 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 = 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 = 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 = 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 = 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 = 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}; + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; @@ -6857,7 +6975,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, 0, 42).unwrap(); + let mut node_a_chan = Channel::::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).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()); @@ -6871,7 +6989,7 @@ mod tests { flags: 0, cltv_expiry_delta: 100, htlc_minimum_msat: 5, - htlc_maximum_msat: OptionalField::Absent, + htlc_maximum_msat: MAX_VALUE_MSAT, fee_base_msat: 110, fee_proportional_millionths: 11, excess_data: Vec::new(), @@ -6935,8 +7053,8 @@ mod tests { let counterparty_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let mut config = UserConfig::default(); - config.own_channel_config.announced_channel = false; - let mut chan = Channel::::new_outbound(&&feeest, &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0, 42).unwrap(); // Nothing uses their network key in this test + config.channel_handshake_config.announced_channel = false; + let mut chan = Channel::::new_outbound(&LowerBoundedFeeEstimator::new(&feeest), &&keys_provider, counterparty_node_id, &InitFeatures::known(), 10_000_000, 100000, 42, &config, 0, 42).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 @@ -7774,7 +7892,7 @@ mod tests { #[test] fn test_zero_conf_channel_type_support() { - let feeest = TestFeeEstimator{fee_est: 15000}; + let feeest = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000}); let secp_ctx = Secp256k1::new(); let seed = [42; 32]; let network = Network::Testnet; @@ -7783,7 +7901,7 @@ mod tests { let node_b_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(&&feeest, &&keys_provider, + let node_a_chan = Channel::::new_outbound(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), 10000000, 100000, 42, &config, 0, 42).unwrap(); let mut channel_type_features = ChannelTypeFeatures::only_static_remote_key(); @@ -7792,7 +7910,7 @@ mod tests { let mut open_channel_msg = node_a_chan.get_open_channel(genesis_block(network).header.block_hash()); open_channel_msg.channel_type = Some(channel_type_features); let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap()); - let res = Channel::::new_from_req(&&feeest, &&keys_provider, + let res = Channel::::new_from_req(&feeest, &&keys_provider, node_b_node_id, &InitFeatures::known(), &open_channel_msg, 7, &config, 0, &&logger, 42); assert!(res.is_ok()); }