Require inbound channels with anchor outputs to be accepted manually
authorWilmer Paulino <wilmer@wilmerpaulino.com>
Tue, 20 Jun 2023 19:14:48 +0000 (12:14 -0700)
committerWilmer Paulino <wilmer@wilmerpaulino.com>
Fri, 23 Jun 2023 22:57:46 +0000 (15:57 -0700)
Since the use of channels with anchor outputs requires a reserve of
onchain funds to handle channel force closures, it would be
irresponsible to allow a node to accept inbound channel without first
consulting such reserves. To allow users to do so, we require such
channels be manually accepted.

lightning/src/ln/channelmanager.rs
lightning/src/ln/monitor_tests.rs
lightning/src/util/config.rs

index 9cea6500d3e63b6754cc5406f1aa09325ac57d42..a8e19e738e348e17f7c1dace3952d260c0ba995c 100644 (file)
@@ -5103,9 +5103,13 @@ where
                        return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision for the same peer!".to_owned(), msg.temporary_channel_id.clone()))
                } else {
                        if !self.default_configuration.manually_accept_inbound_channels {
-                               if channel.context.get_channel_type().requires_zero_conf() {
+                               let channel_type = channel.context.get_channel_type();
+                               if channel_type.requires_zero_conf() {
                                        return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), msg.temporary_channel_id.clone()));
                                }
+                               if channel_type.requires_anchors_zero_fee_htlc_tx() {
+                                       return Err(MsgHandleErrInternal::send_err_msg_no_close("No channels with anchor outputs accepted".to_owned(), msg.temporary_channel_id.clone()));
+                               }
                                peer_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
                                        node_id: counterparty_node_id.clone(),
                                        msg: channel.accept_inbound_channel(user_channel_id),
@@ -8732,7 +8736,7 @@ mod tests {
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
        use crate::ln::channelmanager::{inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
        use crate::ln::functional_test_utils::*;
-       use crate::ln::msgs;
+       use crate::ln::msgs::{self, ErrorAction};
        use crate::ln::msgs::ChannelMessageHandler;
        use crate::routing::router::{PaymentParameters, RouteParameters, find_route};
        use crate::util::errors::APIError;
@@ -9728,6 +9732,50 @@ mod tests {
                        sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat)).is_ok());
        }
 
+       #[test]
+       fn test_inbound_anchors_manual_acceptance() {
+               // Tests that we properly limit inbound channels when we have the manual-channel-acceptance
+               // flag set and (sometimes) accept channels as 0conf.
+               let mut anchors_cfg = test_default_channel_config();
+               anchors_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+
+               let mut anchors_manual_accept_cfg = anchors_cfg.clone();
+               anchors_manual_accept_cfg.manually_accept_inbound_channels = true;
+
+               let chanmon_cfgs = create_chanmon_cfgs(3);
+               let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+               let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs,
+                       &[Some(anchors_cfg.clone()), Some(anchors_cfg.clone()), Some(anchors_manual_accept_cfg.clone())]);
+               let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+               nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None).unwrap();
+               let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+
+               nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
+               assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+               let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+               match &msg_events[0] {
+                       MessageSendEvent::HandleError { node_id, action } => {
+                               assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+                               match action {
+                                       ErrorAction::SendErrorMessage { msg } =>
+                                               assert_eq!(msg.data, "No channels with anchor outputs accepted".to_owned()),
+                                       _ => panic!("Unexpected error action"),
+                               }
+                       }
+                       _ => panic!("Unexpected event"),
+               }
+
+               nodes[2].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
+               let events = nodes[2].node.get_and_clear_pending_events();
+               match events[0] {
+                       Event::OpenChannelRequest { temporary_channel_id, .. } =>
+                               nodes[2].node.accept_inbound_channel(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 23).unwrap(),
+                       _ => panic!("Unexpected event"),
+               }
+               get_event_msg!(nodes[2], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
+       }
+
        #[test]
        fn test_anchors_zero_fee_htlc_tx_fallback() {
                // Tests that if both nodes support anchors, but the remote node does not want to accept
index 9ac79ad9008cff4f4a9f6d1b0d6739f446fc701e..2a3f5849b95d07f46e6e393bed08d4919d3f1272 100644 (file)
@@ -1721,6 +1721,7 @@ fn do_test_monitor_rebroadcast_pending_claims(anchors: bool) {
        let mut config = test_default_channel_config();
        if anchors {
                config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               config.manually_accept_inbound_channels = true;
        }
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
@@ -1870,6 +1871,7 @@ fn test_yield_anchors_events() {
        let mut anchors_config = UserConfig::default();
        anchors_config.channel_handshake_config.announced_channel = true;
        anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+       anchors_config.manually_accept_inbound_channels = true;
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
@@ -2002,6 +2004,7 @@ fn test_anchors_aggregated_revoked_htlc_tx() {
        let mut anchors_config = UserConfig::default();
        anchors_config.channel_handshake_config.announced_channel = true;
        anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+       anchors_config.manually_accept_inbound_channels = true;
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config), Some(anchors_config)]);
 
        let bob_persister: test_utils::TestPersister;
index bfa5e08ea03dd3dcbcd76b6d535f55c6b66e74b5..5c8d5b6c554fc11ad4f89500a69f8f600812ad66 100644 (file)
@@ -153,6 +153,12 @@ pub struct ChannelHandshakeConfig {
        /// channels. This feature requires having a reserve of onchain funds readily available to bump
        /// transactions in the event of a channel force close to avoid the possibility of losing funds.
        ///
+       /// Note that if you wish accept inbound channels with anchor outputs, you must enable
+       /// [`UserConfig::manually_accept_inbound_channels`] and manually accept them with
+       /// [`ChannelManager::accept_inbound_channel`]. This is done to give you the chance to check
+       /// whether your reserve of onchain funds is enough to cover the fees for all existing and new
+       /// channels featuring anchor outputs in the event of a force close.
+       ///
        /// If this option is set, channels may be created that will not be readable by LDK versions
        /// prior to 0.0.116, causing [`ChannelManager`]'s read method to return a
        /// [`DecodeError::InvalidValue`].
@@ -168,6 +174,7 @@ pub struct ChannelHandshakeConfig {
        /// Default value: false. This value is likely to change to true in the future.
        ///
        /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+       /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
        /// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
        /// [`SIGHASH_SINGLE + update_fee Considered Harmful`]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html
        pub negotiate_anchors_zero_fee_htlc_tx: bool,