Merge pull request #2333 from benthecarman/chan-mon-bal-helper
[rust-lightning] / lightning / src / ln / channelmanager.rs
index a41fb676e935746b25dd9903405d323f5fe5e754..50e65db3f67dabc6227491b634e93cb404c51787 100644 (file)
@@ -19,7 +19,7 @@
 
 use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::Transaction;
-use bitcoin::blockdata::constants::genesis_block;
+use bitcoin::blockdata::constants::{genesis_block, ChainHash};
 use bitcoin::network::constants::Network;
 
 use bitcoin::hashes::Hash;
@@ -56,7 +56,7 @@ use crate::ln::outbound_payment;
 use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment};
 use crate::ln::wire::Encode;
 use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner, WriteableEcdsaChannelSigner};
-use crate::util::config::{UserConfig, ChannelConfig};
+use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
 use crate::util::wakers::{Future, Notifier};
 use crate::util::scid_utils::fake_scid;
 use crate::util::string::UntrustedString;
@@ -1373,8 +1373,14 @@ pub struct ChannelDetails {
        /// the current state and per-HTLC limit(s). This is intended for use when routing, allowing us
        /// to use a limit as close as possible to the HTLC limit we can currently send.
        ///
-       /// See also [`ChannelDetails::balance_msat`] and [`ChannelDetails::outbound_capacity_msat`].
+       /// See also [`ChannelDetails::next_outbound_htlc_minimum_msat`],
+       /// [`ChannelDetails::balance_msat`], and [`ChannelDetails::outbound_capacity_msat`].
        pub next_outbound_htlc_limit_msat: u64,
+       /// The minimum value for sending a single HTLC to the remote peer. This is the equivalent of
+       /// [`ChannelDetails::next_outbound_htlc_limit_msat`] but represents a lower-bound, rather than
+       /// an upper-bound. This is intended for use when routing, allowing us to ensure we pick a
+       /// route which is valid.
+       pub next_outbound_htlc_minimum_msat: u64,
        /// The available inbound capacity for the remote peer to send HTLCs to us. This does not
        /// include any pending HTLCs which are not yet fully resolved (and, thus, whose balance is not
        /// available for inclusion in new inbound HTLCs).
@@ -1494,6 +1500,7 @@ impl ChannelDetails {
                        inbound_capacity_msat: balance.inbound_capacity_msat,
                        outbound_capacity_msat: balance.outbound_capacity_msat,
                        next_outbound_htlc_limit_msat: balance.next_outbound_htlc_limit_msat,
+                       next_outbound_htlc_minimum_msat: balance.next_outbound_htlc_minimum_msat,
                        user_channel_id: channel.get_user_id(),
                        confirmations_required: channel.minimum_depth(),
                        confirmations: Some(channel.get_funding_tx_confirmations(best_block_height)),
@@ -3228,7 +3235,7 @@ where
                })
        }
 
-       /// Atomically updates the [`ChannelConfig`] for the given channels.
+       /// Atomically applies partial updates to the [`ChannelConfig`] of the given channels.
        ///
        /// Once the updates are applied, each eligible channel (advertised with a known short channel
        /// ID and a change in [`forwarding_fee_proportional_millionths`], [`forwarding_fee_base_msat`],
@@ -3250,10 +3257,10 @@ where
        /// [`ChannelUpdate`]: msgs::ChannelUpdate
        /// [`ChannelUnavailable`]: APIError::ChannelUnavailable
        /// [`APIMisuseError`]: APIError::APIMisuseError
-       pub fn update_channel_config(
-               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config: &ChannelConfig,
+       pub fn update_partial_channel_config(
+               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config_update: &ChannelConfigUpdate,
        ) -> Result<(), APIError> {
-               if config.cltv_expiry_delta < MIN_CLTV_EXPIRY_DELTA {
+               if config_update.cltv_expiry_delta.map(|delta| delta < MIN_CLTV_EXPIRY_DELTA).unwrap_or(false) {
                        return Err(APIError::APIMisuseError {
                                err: format!("The chosen CLTV expiry delta is below the minimum of {}", MIN_CLTV_EXPIRY_DELTA),
                        });
@@ -3274,7 +3281,9 @@ where
                }
                for channel_id in channel_ids {
                        let channel = peer_state.channel_by_id.get_mut(channel_id).unwrap();
-                       if !channel.update_config(config) {
+                       let mut config = channel.config();
+                       config.apply(config_update);
+                       if !channel.update_config(&config) {
                                continue;
                        }
                        if let Ok(msg) = self.get_channel_update_for_broadcast(channel) {
@@ -3289,6 +3298,34 @@ where
                Ok(())
        }
 
+       /// Atomically updates the [`ChannelConfig`] for the given channels.
+       ///
+       /// Once the updates are applied, each eligible channel (advertised with a known short channel
+       /// ID and a change in [`forwarding_fee_proportional_millionths`], [`forwarding_fee_base_msat`],
+       /// or [`cltv_expiry_delta`]) has a [`BroadcastChannelUpdate`] event message generated
+       /// containing the new [`ChannelUpdate`] message which should be broadcast to the network.
+       ///
+       /// Returns [`ChannelUnavailable`] when a channel is not found or an incorrect
+       /// `counterparty_node_id` is provided.
+       ///
+       /// Returns [`APIMisuseError`] when a [`cltv_expiry_delta`] update is to be applied with a value
+       /// below [`MIN_CLTV_EXPIRY_DELTA`].
+       ///
+       /// If an error is returned, none of the updates should be considered applied.
+       ///
+       /// [`forwarding_fee_proportional_millionths`]: ChannelConfig::forwarding_fee_proportional_millionths
+       /// [`forwarding_fee_base_msat`]: ChannelConfig::forwarding_fee_base_msat
+       /// [`cltv_expiry_delta`]: ChannelConfig::cltv_expiry_delta
+       /// [`BroadcastChannelUpdate`]: events::MessageSendEvent::BroadcastChannelUpdate
+       /// [`ChannelUpdate`]: msgs::ChannelUpdate
+       /// [`ChannelUnavailable`]: APIError::ChannelUnavailable
+       /// [`APIMisuseError`]: APIError::APIMisuseError
+       pub fn update_channel_config(
+               &self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config: &ChannelConfig,
+       ) -> Result<(), APIError> {
+               return self.update_partial_channel_config(counterparty_node_id, channel_ids, &(*config).into());
+       }
+
        /// Attempts to forward an intercepted HTLC over the provided channel id and with the provided
        /// amount to forward. Should only be called in response to an [`HTLCIntercepted`] event.
        ///
@@ -6987,6 +7024,10 @@ where
                provided_init_features(&self.default_configuration)
        }
 
+       fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>> {
+               Some(vec![ChainHash::from(&self.genesis_hash[..])])
+       }
+
        fn handle_tx_add_input(&self, counterparty_node_id: &PublicKey, msg: &msgs::TxAddInput) {
                let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
                        "Dual-funded channels not supported".to_owned(),
@@ -7136,10 +7177,9 @@ impl Writeable for ChannelDetails {
                        (14, user_channel_id_low, required),
                        (16, self.balance_msat, required),
                        (18, self.outbound_capacity_msat, required),
-                       // Note that by the time we get past the required read above, outbound_capacity_msat will be
-                       // filled in, so we can safely unwrap it here.
-                       (19, self.next_outbound_htlc_limit_msat, (default_value, outbound_capacity_msat.0.unwrap() as u64)),
+                       (19, self.next_outbound_htlc_limit_msat, required),
                        (20, self.inbound_capacity_msat, required),
+                       (21, self.next_outbound_htlc_minimum_msat, required),
                        (22, self.confirmations_required, option),
                        (24, self.force_close_spend_delay, option),
                        (26, self.is_outbound, required),
@@ -7176,6 +7216,7 @@ impl Readable for ChannelDetails {
                        // filled in, so we can safely unwrap it here.
                        (19, next_outbound_htlc_limit_msat, (default_value, outbound_capacity_msat.0.unwrap() as u64)),
                        (20, inbound_capacity_msat, required),
+                       (21, next_outbound_htlc_minimum_msat, (default_value, 0)),
                        (22, confirmations_required, option),
                        (24, force_close_spend_delay, option),
                        (26, is_outbound, required),
@@ -7209,6 +7250,7 @@ impl Readable for ChannelDetails {
                        balance_msat: balance_msat.0.unwrap(),
                        outbound_capacity_msat: outbound_capacity_msat.0.unwrap(),
                        next_outbound_htlc_limit_msat: next_outbound_htlc_limit_msat.0.unwrap(),
+                       next_outbound_htlc_minimum_msat: next_outbound_htlc_minimum_msat.0.unwrap(),
                        inbound_capacity_msat: inbound_capacity_msat.0.unwrap(),
                        confirmations_required,
                        confirmations,
@@ -8578,7 +8620,7 @@ mod tests {
        use crate::routing::router::{PaymentParameters, RouteParameters, find_route};
        use crate::util::errors::APIError;
        use crate::util::test_utils;
-       use crate::util::config::ChannelConfig;
+       use crate::util::config::{ChannelConfig, ChannelConfigUpdate};
        use crate::sign::EntropySource;
 
        #[test]
@@ -9297,12 +9339,14 @@ mod tests {
                                &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                        peer_pks.push(random_pk);
                        nodes[1].node.peer_connected(&random_pk, &msgs::Init {
-                               features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+                       }, true).unwrap();
                }
                let last_random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                        &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap_err();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap_err();
 
                // Also importantly, because nodes[0] isn't "protected", we will refuse a reconnection from
                // them if we have too many un-channel'd peers.
@@ -9313,13 +9357,16 @@ mod tests {
                        if let Event::ChannelClosed { .. } = ev { } else { panic!(); }
                }
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap_err();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap_err();
 
                // but of course if the connection is outbound its allowed...
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, false).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
 
                // Now nodes[0] is disconnected but still has a pending, un-funded channel lying around.
@@ -9343,7 +9390,8 @@ mod tests {
                // "protected" and can connect again.
                mine_transaction(&nodes[1], funding_tx.as_ref().unwrap());
                nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                get_event_msg!(nodes[1], MessageSendEvent::SendChannelReestablish, nodes[0].node.get_our_node_id());
 
                // Further, because the first channel was funded, we can open another channel with
@@ -9408,7 +9456,8 @@ mod tests {
                        let random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                                &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                        nodes[1].node.peer_connected(&random_pk, &msgs::Init {
-                               features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                               features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+                       }, true).unwrap();
 
                        nodes[1].node.handle_open_channel(&random_pk, &open_channel_msg);
                        let events = nodes[1].node.get_and_clear_pending_events();
@@ -9426,7 +9475,8 @@ mod tests {
                let last_random_pk = PublicKey::from_secret_key(&nodes[0].node.secp_ctx,
                        &SecretKey::from_slice(&nodes[1].keys_manager.get_secure_random_bytes()).unwrap());
                nodes[1].node.peer_connected(&last_random_pk, &msgs::Init {
-                       features: nodes[0].node.init_features(), remote_network_address: None }, true).unwrap();
+                       features: nodes[0].node.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
                nodes[1].node.handle_open_channel(&last_random_pk, &open_channel_msg);
                let events = nodes[1].node.get_and_clear_pending_events();
                match events[0] {
@@ -9489,6 +9539,62 @@ mod tests {
 
                check_closed_event!(nodes[1], 1, ClosureReason::HolderForceClosed);
        }
+
+       #[test]
+       fn test_update_channel_config() {
+               let chanmon_cfg = create_chanmon_cfgs(2);
+               let node_cfg = create_node_cfgs(2, &chanmon_cfg);
+               let mut user_config = test_default_channel_config();
+               let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[Some(user_config), Some(user_config)]);
+               let nodes = create_network(2, &node_cfg, &node_chanmgr);
+               let _ = create_announced_chan_between_nodes(&nodes, 0, 1);
+               let channel = &nodes[0].node.list_channels()[0];
+
+               nodes[0].node.update_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &user_config.channel_config).unwrap();
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 0);
+
+               user_config.channel_config.forwarding_fee_base_msat += 10;
+               nodes[0].node.update_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &user_config.channel_config).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_base_msat, user_config.channel_config.forwarding_fee_base_msat);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate::default()).unwrap();
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 0);
+
+               let new_cltv_expiry_delta = user_config.channel_config.cltv_expiry_delta + 6;
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate {
+                       cltv_expiry_delta: Some(new_cltv_expiry_delta),
+                       ..Default::default()
+               }).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().cltv_expiry_delta, new_cltv_expiry_delta);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+
+               let new_fee = user_config.channel_config.forwarding_fee_proportional_millionths + 100;
+               nodes[0].node.update_partial_channel_config(&channel.counterparty.node_id, &[channel.channel_id], &ChannelConfigUpdate {
+                       forwarding_fee_proportional_millionths: Some(new_fee),
+                       ..Default::default()
+               }).unwrap();
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().cltv_expiry_delta, new_cltv_expiry_delta);
+               assert_eq!(nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths, new_fee);
+               let events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(events.len(), 1);
+               match &events[0] {
+                       MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+                       _ => panic!("expected BroadcastChannelUpdate event"),
+               }
+       }
 }
 
 #[cfg(ldk_bench)]
@@ -9570,8 +9676,12 @@ pub mod bench {
                });
                let node_b_holder = ANodeHolder { node: &node_b };
 
-               node_a.peer_connected(&node_b.get_our_node_id(), &Init { features: node_b.init_features(), remote_network_address: None }, true).unwrap();
-               node_b.peer_connected(&node_a.get_our_node_id(), &Init { features: node_a.init_features(), remote_network_address: None }, false).unwrap();
+               node_a.peer_connected(&node_b.get_our_node_id(), &Init {
+                       features: node_b.init_features(), networks: None, remote_network_address: None
+               }, true).unwrap();
+               node_b.peer_connected(&node_a.get_our_node_id(), &Init {
+                       features: node_a.init_features(), networks: None, remote_network_address: None
+               }, false).unwrap();
                node_a.create_channel(node_b.get_our_node_id(), 8_000_000, 100_000_000, 42, None).unwrap();
                node_b.handle_open_channel(&node_a.get_our_node_id(), &get_event_msg!(node_a_holder, MessageSendEvent::SendOpenChannel, node_b.get_our_node_id()));
                node_a.handle_accept_channel(&node_b.get_our_node_id(), &get_event_msg!(node_b_holder, MessageSendEvent::SendAcceptChannel, node_a.get_our_node_id()));