Skip to content

Commit e757cca

Browse files
committed
Add API and signaling to accept incoming channels at 0conf
1 parent e55ff01 commit e757cca

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

lightning/src/ln/channel.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ impl<Signer: Sign> Channel<Signer> {
12651265
counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
12661266
holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat },
12671267
counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
1268-
minimum_depth: Some(config.own_channel_config.minimum_depth),
1268+
minimum_depth: Some(cmp::max(config.own_channel_config.minimum_depth, 1)),
12691269

12701270
counterparty_forwarding_info: None,
12711271

@@ -4797,6 +4797,12 @@ impl<Signer: Sign> Channel<Signer> {
47974797
self.inbound_awaiting_accept
47984798
}
47994799

4800+
/// Sets this channel to accepting 0conf, must be done before `get_accept_channel`
4801+
pub fn set_0conf(&mut self) {
4802+
assert!(self.inbound_awaiting_accept);
4803+
self.minimum_depth = Some(0);
4804+
}
4805+
48004806
/// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannel`] message which
48014807
/// should be sent back to the counterparty node.
48024808
///

lightning/src/ln/channelmanager.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4352,18 +4352,43 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
43524352
}
43534353
}
43544354

4355-
/// Called to accept a request to open a channel after [`Event::OpenChannelRequest`] has been
4356-
/// triggered.
4355+
/// Accepts a request to open a channel after a [`Event::OpenChannelRequest`].
43574356
///
43584357
/// The `temporary_channel_id` parameter indicates which inbound channel should be accepted.
43594358
///
4360-
/// For inbound channels, the `user_channel_id` parameter will be provided back in
4359+
/// The `user_channel_id` parameter will be provided back in
43614360
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
43624361
/// with which `accept_inbound_channel` call.
43634362
///
43644363
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
43654364
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
43664365
pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], user_channel_id: u64) -> Result<(), APIError> {
4366+
self.do_accept_inbound_channel(temporary_channel_id, false, user_channel_id)
4367+
}
4368+
4369+
/// Accepts a request to open a channel after a [`events::Event::OpenChannelRequest`], treating
4370+
/// it as confirmed immediately.
4371+
///
4372+
/// The `user_channel_id` parameter will be provided back in
4373+
/// [`Event::ChannelClosed::user_channel_id`] to allow tracking of which events correspond
4374+
/// with which `accept_inbound_channel` call.
4375+
///
4376+
/// Unlike [`ChannelManager::accept_inbound_channel`], this method accepts the incoming channel
4377+
/// and (if the counterparty agrees), enables forwarding of payments immediately.
4378+
///
4379+
/// This fully trusts that the counterparty has honestly and correctly constructed the funding
4380+
/// transaction and blindly assumes that it will eventually confirm.
4381+
///
4382+
/// If it does not confirm before we decide to close the channel, or if the funding transaction
4383+
/// does not pay to the correct script the correct amount, *you will lose funds*.
4384+
///
4385+
/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
4386+
/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
4387+
pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &[u8; 32], user_channel_id: u64) -> Result<(), APIError> {
4388+
self.do_accept_inbound_channel(temporary_channel_id, true, user_channel_id)
4389+
}
4390+
4391+
fn do_accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], accept_0conf: bool, user_channel_id: u64) -> Result<(), APIError> {
43674392
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
43684393

43694394
let mut channel_state_lock = self.channel_state.lock().unwrap();
@@ -4373,6 +4398,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
43734398
if !channel.get().inbound_is_awaiting_accept() {
43744399
return Err(APIError::APIMisuseError { err: "The channel isn't currently awaiting to be accepted.".to_owned() });
43754400
}
4401+
if accept_0conf { channel.get_mut().set_0conf(); }
43764402
channel_state.pending_msg_events.push(events::MessageSendEvent::SendAcceptChannel {
43774403
node_id: channel.get().get_counterparty_node_id(),
43784404
msg: channel.get_mut().accept_inbound_channel(user_channel_id),

lightning/src/ln/priv_short_conf_tests.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,15 +550,27 @@ fn test_simple_0_conf_channel() {
550550

551551
let chanmon_cfgs = create_chanmon_cfgs(2);
552552
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
553-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
553+
let mut chan_config = test_default_channel_config();
554+
chan_config.manually_accept_inbound_channels = true;
555+
556+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(chan_config)]);
554557
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
555558

556559
nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100000, 10001, 42, None).unwrap();
557560
let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
558561

559562
nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel);
563+
let events = nodes[1].node.get_and_clear_pending_events();
564+
assert_eq!(events.len(), 1);
565+
match events[0] {
566+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
567+
nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, 0).unwrap();
568+
},
569+
_ => panic!("Unexpected event"),
570+
};
571+
560572
let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
561-
accept_channel.minimum_depth = 0;
573+
assert_eq!(accept_channel.minimum_depth, 0);
562574
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel);
563575

564576
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], 100000, 42);

lightning/src/util/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ pub struct ChannelHandshakeConfig {
2121
/// Applied only for inbound channels (see ChannelHandshakeLimits::max_minimum_depth for the
2222
/// equivalent limit applied to outbound channels).
2323
///
24+
/// A lower-bound of 1 is applied, requiring all channels to have a confirmed commitment
25+
/// transaction before operation. If you wish to accept channels with zero confirmations, see
26+
/// [`UserConfig::manually_accept_inbound_channels`] and
27+
/// [`ChannelManager::accept_inbound_channel`].
28+
///
2429
/// Default value: 6.
30+
///
31+
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
2532
pub minimum_depth: u32,
2633
/// Set to the number of blocks we require our counterparty to wait to claim their money (ie
2734
/// the number of blocks we have to punish our counterparty if they broadcast a revoked

0 commit comments

Comments
 (0)