From 9569bfe820a4c2053b3842ddce0080c9c9dd9a44 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 2 Feb 2022 23:01:05 +0000 Subject: [PATCH] Add API and signaling to accept incoming channels at 0conf --- lightning/src/ln/channel.rs | 8 +++++- lightning/src/ln/channelmanager.rs | 34 ++++++++++++++++++++--- lightning/src/ln/priv_short_conf_tests.rs | 16 +++++++++-- lightning/src/util/config.rs | 8 ++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f221ee62..a49444f0 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1312,7 +1312,7 @@ impl Channel { 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, - minimum_depth: Some(config.own_channel_config.minimum_depth), + minimum_depth: Some(cmp::max(config.own_channel_config.minimum_depth, 1)), counterparty_forwarding_info: None, @@ -4878,6 +4878,12 @@ impl Channel { self.inbound_awaiting_accept } + /// Sets this channel to accepting 0conf, must be done before `get_accept_channel` + pub fn set_0conf(&mut self) { + assert!(self.inbound_awaiting_accept); + self.minimum_depth = Some(0); + } + /// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannel`] message which /// should be sent back to the counterparty node. /// diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 5f65a66c..acc1310f 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -4119,20 +4119,45 @@ impl ChannelMana } } - /// Called to accept a request to open a channel after [`Event::OpenChannelRequest`] has been - /// triggered. + /// Accepts a request to open a channel after a [`Event::OpenChannelRequest`]. /// /// The `temporary_channel_id` parameter indicates which inbound channel should be accepted, /// and the `counterparty_node_id` parameter is the id of the peer which has requested to open /// the channel. /// - /// For inbound channels, the `user_channel_id` parameter will be provided back in + /// The `user_channel_id` parameter will be provided back in /// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond - /// with which `accept_inbound_channel` call. + /// with which `accept_inbound_channel`/`accept_inbound_channel_from_trusted_peer_0conf` call. /// /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u64) -> Result<(), APIError> { + self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id) + } + + /// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating + /// it as confirmed immediately. + /// + /// The `user_channel_id` parameter will be provided back in + /// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond + /// with which `accept_inbound_channel`/`accept_inbound_channel_from_trusted_peer_0conf` call. + /// + /// Unlike [`ChannelManager::accept_inbound_channel`], this method accepts the incoming channel + /// and (if the counterparty agrees), enables forwarding of payments immediately. + /// + /// This fully trusts that the counterparty has honestly and correctly constructed the funding + /// transaction and blindly assumes that it will eventually confirm. + /// + /// If it does not confirm before we decide to close the channel, or if the funding transaction + /// does not pay to the correct script the correct amount, *you will lose funds*. + /// + /// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest + /// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id + pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u64) -> Result<(), APIError> { + self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id) + } + + fn do_accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, accept_0conf: bool, user_channel_id: u64) -> Result<(), APIError> { let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); let mut channel_state_lock = self.channel_state.lock().unwrap(); @@ -4145,6 +4170,7 @@ impl ChannelMana if *counterparty_node_id != channel.get().get_counterparty_node_id() { return Err(APIError::APIMisuseError { err: "The passed counterparty_node_id doesn't match the channel's counterparty node_id".to_owned() }); } + if accept_0conf { channel.get_mut().set_0conf(); } channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel { node_id: channel.get().get_counterparty_node_id(), msg: channel.get_mut().accept_inbound_channel(user_channel_id), diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index 48dab6a2..a7bc3e56 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -573,15 +573,27 @@ fn test_simple_0conf_channel() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); - let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let mut chan_config = test_default_channel_config(); + chan_config.manually_accept_inbound_channels = true; + + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(chan_config)]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap(); let open_channel = 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(), InitFeatures::known(), &open_channel); + let events = nodes[1].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::OpenChannelRequest { temporary_channel_id, .. } => { + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + }, + _ => panic!("Unexpected event"), + }; + let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); - accept_channel.minimum_depth = 0; + assert_eq!(accept_channel.minimum_depth, 0); nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel); let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42); diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index 4d1c7c99..bdd222e3 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -22,7 +22,15 @@ pub struct ChannelHandshakeConfig { /// Applied only for inbound channels (see ChannelHandshakeLimits::max_minimum_depth for the /// equivalent limit applied to outbound channels). /// + /// A lower-bound of 1 is applied, requiring all channels to have a confirmed commitment + /// transaction before operation. If you wish to accept channels with zero confirmations, see + /// [`UserConfig::manually_accept_inbound_channels`] and + /// [`ChannelManager::accept_inbound_channel_from_trusted_peer_0conf`]. + /// /// Default value: 6. + /// + /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel + /// [`ChannelManager::accept_inbound_channel_from_trusted_peer_0conf`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel_from_trusted_peer_0conf pub minimum_depth: u32, /// Set to the number of blocks we require our counterparty to wait to claim their money (ie /// the number of blocks we have to punish our counterparty if they broadcast a revoked -- 2.30.2