-
Notifications
You must be signed in to change notification settings - Fork 339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement V2 channel establishment #2302
base: main
Are you sure you want to change the base?
Conversation
34b5cef
to
5bd6e42
Compare
5bd6e42
to
cc88119
Compare
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #2302 +/- ##
==========================================
- Coverage 89.90% 89.89% -0.01%
==========================================
Files 117 117
Lines 97415 98059 +644
Branches 97415 98059 +644
==========================================
+ Hits 87581 88152 +571
- Misses 7272 7341 +69
- Partials 2562 2566 +4 ☔ View full report in Codecov by Sentry. |
cc88119
to
6de5a2d
Compare
6de5a2d
to
d155b0e
Compare
This isn't blocked on anything anymore, right? Is there anything you want early feedback on here? |
Technically blocked on interactive txs. But yeah, a few things I need to update before some conceptual/approach review here. |
Also now blocked on the 2077 fixups. |
d155b0e
to
c861c67
Compare
If this is blocked on review interactive txs on the spec-side, I can do a round here. Though dunno which PRs it’s blocked on. |
Oh sorry, I meant the interactive txs implementation. Jurvis had two sketches up in his fork and will be putting a PR together as per the first action item here: https://gist.github.com/jurvis/98215abd6fd392a3f2f0ded03c5c6fff. |
c861c67
to
335ab6f
Compare
@jurvis If you have a branch available for early conceptual review, happy to have a look and see how it scores compared to the specification, the ongoing changes in the mempool and LDK current interfaces :) |
@ariard we just finalised an approach for the TX constructor we are happy with so I’m working to put together a proof of concept rn for review. Should be ready in the next couple of days! |
Many thanks, left a couple of review feedback on the new poc PR. If Duncan or you can maintain a dual-funding / splicing issue like Wilmer is doing for anchor output, this is very welcome to coordinate review and pin feedback backlog. I’ll have a look on the gist too, have to catchup with spec first. |
335ab6f
to
6099dbf
Compare
6099dbf
to
e50d576
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly a high-level pass.
lightning/src/ln/channel.rs
Outdated
/// The current interactive transaction construction session under negotiation. | ||
#[cfg(dual_funding)] | ||
interactive_tx_constructor: Option<InteractiveTxConstructor>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than putting this in the context, should this go only in the relevant ChannelPhase
variants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could always still be populated in an ordinary Channel
too because of splicing. In fact we keep it around after promoting inbound and outbound V2 channels to Channel
since we still need to complete the interactive signing at that point.
I could triplicate this in InboundV2Channel
, OutboundV2Channel
, and Channel
if that makes more sense, and then the V1 unfunded channels wouldn't have access to it. I'm mostly indifferent to that. So if it's preferred I'll do that! :)
lightning/src/ln/channelmanager.rs
Outdated
ChannelPhase::UnfundedInboundV2(ref mut channel) => { | ||
channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id) | ||
}, | ||
ChannelPhase::UnfundedOutboundV2(ref mut channel) => { | ||
channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id) | ||
}, | ||
_ => try_chan_phase_entry!(self, Err(ChannelError::Warn( | ||
"Got a tx_add_input message with no interactive transaction construction expected or in-progress" | ||
.into())), chan_phase_entry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to my other comment about putting the InteractiveTxConstructor
in the relevant phase variants, would that remove the need for the InteractivelyFunded
trait? Seems the check here is essentially being repeated there. And here the context is available so you don't need HasChannelContext
if all the code in InteractivelyFunded
were inlined in these methods. Just feels like this could be simplified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, those methods were inlined in the respective variants in the previous iteration. We had quite a bit of duplication before. I'll look into simplifying without re-introducing the duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking something like this:
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 1f65d064d..185daec8d 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -1243,6 +1243,19 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
ChannelPhase::UnfundedInboundV2(ref mut chan) => &mut chan.context,
}
}
+
+ #[cfg(any(dual_funding, splicing))]
+ pub fn interactive_tx_constructor_mut(&'a mut self) -> Result<Option<&'a mut InteractiveTxConstructor>, ()> {
+ match self {
+ ChannelPhase::Funded(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ ChannelPhase::UnfundedOutboundV1(ref mut chan) => Err(()),
+ ChannelPhase::UnfundedInboundV1(ref mut chan) => Err(()),
+ #[cfg(any(dual_funding, splicing))]
+ ChannelPhase::UnfundedOutboundV2(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ #[cfg(any(dual_funding, splicing))]
+ ChannelPhase::UnfundedInboundV2(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ }
+ }
}
/// Contains all state common to unfunded inbound/outbound channels.
@@ -1652,17 +1665,6 @@ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider
Ok(msg)
}
- fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
- InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
- Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
- |reason| reason.into_tx_abort_msg(self.context_mut().channel_id())),
- None => Err(msgs::TxAbort {
- channel_id: self.context_mut().channel_id(),
- data: "We do not have an interactive transaction negotiation in progress".to_string().into_bytes()
- }),
- })
- }
-
fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 7f1000ab9..077e022cb 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -53,7 +53,7 @@ use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFea
#[cfg(any(feature = "_test_utils", test))]
use crate::ln::features::Bolt11InvoiceFeatures;
#[cfg(any(dual_funding, splicing))]
-use crate::ln::interactivetxs::InteractiveTxMessageSend;
+use crate::ln::interactivetxs::{InteractiveTxMessageSend, InteractiveTxMessageSendResult};
use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router};
use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails};
use crate::ln::msgs;
@@ -7864,18 +7864,23 @@ where
match peer_state.channel_by_id.entry(msg.channel_id) {
hash_map::Entry::Occupied(mut chan_phase_entry) => {
let channel_phase = chan_phase_entry.get_mut();
- let msg_send_event = match channel_phase {
- ChannelPhase::UnfundedInboundV2(ref mut channel) => {
- channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id)
- },
- ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
- channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id)
+ let msg_send_event = match channel_phase.interactive_tx_constructor_mut() {
+ Ok(Some(tx_constructor)) => {
+ tx_constructor
+ .handle_tx_add_input(msg)
+ .map_err(|reason| reason.into_tx_abort_msg(channel_phase.context_mut().channel_id()))
},
- _ => try_chan_phase_entry!(self, Err(ChannelError::Warn(
+ Ok(None) => Err(msgs::TxAbort {
+ channel_id: channel_phase.context_mut().channel_id(),
+ data: "We do not have an interactive transaction negotiation in progress".to_string().into_bytes(),
+ }),
+ Err(()) => try_chan_phase_entry!(self, Err(ChannelError::Warn(
"Got a tx_add_input message with no interactive transaction construction expected or in-progress"
.into())), chan_phase_entry)
};
- peer_state.pending_msg_events.push(msg_send_event);
+ peer_state.pending_msg_events.push(
+ InteractiveTxMessageSendResult(msg_send_event).into_msg_send_event(counterparty_node_id)
+ );
Ok(())
},
hash_map::Entry::Vacant(_) => {
Though I admit returning a Result
in ChannelPhase::interactive_tx_constructor_mut
might not be ideal. What you have is probably a bit safer, now that I think about it more. And it may be needed for begin_interactive_funding_tx_construction
, anyway.
Just resolved some conflicts and addressed a few comments. Still busy addressing Jeff's other initial review comments. |
953aa81
to
312429f
Compare
b1b9d9d
to
ad11211
Compare
lightning/src/ln/channelmanager.rs
Outdated
ChannelPhase::UnfundedInboundV2(ref mut channel) => { | ||
channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id) | ||
}, | ||
ChannelPhase::UnfundedOutboundV2(ref mut channel) => { | ||
channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id) | ||
}, | ||
_ => try_chan_phase_entry!(self, Err(ChannelError::Warn( | ||
"Got a tx_add_input message with no interactive transaction construction expected or in-progress" | ||
.into())), chan_phase_entry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking something like this:
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 1f65d064d..185daec8d 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -1243,6 +1243,19 @@ impl<'a, SP: Deref> ChannelPhase<SP> where
ChannelPhase::UnfundedInboundV2(ref mut chan) => &mut chan.context,
}
}
+
+ #[cfg(any(dual_funding, splicing))]
+ pub fn interactive_tx_constructor_mut(&'a mut self) -> Result<Option<&'a mut InteractiveTxConstructor>, ()> {
+ match self {
+ ChannelPhase::Funded(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ ChannelPhase::UnfundedOutboundV1(ref mut chan) => Err(()),
+ ChannelPhase::UnfundedInboundV1(ref mut chan) => Err(()),
+ #[cfg(any(dual_funding, splicing))]
+ ChannelPhase::UnfundedOutboundV2(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ #[cfg(any(dual_funding, splicing))]
+ ChannelPhase::UnfundedInboundV2(ref mut chan) => Ok(chan.interactive_tx_constructor.as_mut()),
+ }
+ }
}
/// Contains all state common to unfunded inbound/outbound channels.
@@ -1652,17 +1665,6 @@ pub(super) trait InteractivelyFunded<SP: Deref> where SP::Target: SignerProvider
Ok(msg)
}
- fn tx_add_input(&mut self, msg: &msgs::TxAddInput) -> InteractiveTxMessageSendResult {
- InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
- Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_input(msg).map_err(
- |reason| reason.into_tx_abort_msg(self.context_mut().channel_id())),
- None => Err(msgs::TxAbort {
- channel_id: self.context_mut().channel_id(),
- data: "We do not have an interactive transaction negotiation in progress".to_string().into_bytes()
- }),
- })
- }
-
fn tx_add_output(&mut self, msg: &msgs::TxAddOutput)-> InteractiveTxMessageSendResult {
InteractiveTxMessageSendResult(match self.interactive_tx_constructor_mut() {
Some(ref mut tx_constructor) => tx_constructor.handle_tx_add_output(msg).map_err(
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 7f1000ab9..077e022cb 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -53,7 +53,7 @@ use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFea
#[cfg(any(feature = "_test_utils", test))]
use crate::ln::features::Bolt11InvoiceFeatures;
#[cfg(any(dual_funding, splicing))]
-use crate::ln::interactivetxs::InteractiveTxMessageSend;
+use crate::ln::interactivetxs::{InteractiveTxMessageSend, InteractiveTxMessageSendResult};
use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router};
use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails};
use crate::ln::msgs;
@@ -7864,18 +7864,23 @@ where
match peer_state.channel_by_id.entry(msg.channel_id) {
hash_map::Entry::Occupied(mut chan_phase_entry) => {
let channel_phase = chan_phase_entry.get_mut();
- let msg_send_event = match channel_phase {
- ChannelPhase::UnfundedInboundV2(ref mut channel) => {
- channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id)
- },
- ChannelPhase::UnfundedOutboundV2(ref mut channel) => {
- channel.tx_add_input(msg).into_msg_send_event(counterparty_node_id)
+ let msg_send_event = match channel_phase.interactive_tx_constructor_mut() {
+ Ok(Some(tx_constructor)) => {
+ tx_constructor
+ .handle_tx_add_input(msg)
+ .map_err(|reason| reason.into_tx_abort_msg(channel_phase.context_mut().channel_id()))
},
- _ => try_chan_phase_entry!(self, Err(ChannelError::Warn(
+ Ok(None) => Err(msgs::TxAbort {
+ channel_id: channel_phase.context_mut().channel_id(),
+ data: "We do not have an interactive transaction negotiation in progress".to_string().into_bytes(),
+ }),
+ Err(()) => try_chan_phase_entry!(self, Err(ChannelError::Warn(
"Got a tx_add_input message with no interactive transaction construction expected or in-progress"
.into())), chan_phase_entry)
};
- peer_state.pending_msg_events.push(msg_send_event);
+ peer_state.pending_msg_events.push(
+ InteractiveTxMessageSendResult(msg_send_event).into_msg_send_event(counterparty_node_id)
+ );
Ok(())
},
hash_map::Entry::Vacant(_) => {
Though I admit returning a Result
in ChannelPhase::interactive_tx_constructor_mut
might not be ideal. What you have is probably a bit safer, now that I think about it more. And it may be needed for begin_interactive_funding_tx_construction
, anyway.
5bb4f00
to
ee08373
Compare
ee08373
to
14ca0af
Compare
This PR aims to do the following:
ChannelManager
to create and accept dual-funded channels.contribute_to_dual_funded_channels
if the user would like to contribute inputs to incoming dual-funded channels. In this case, these channels will need to be accepted manually, indicated by a newOpenChannelV2Request
event so that inputs can be provided. If the above flag is false (default), then no inputs will be contributed and the channel is accepted on the user's behalf gated by all the commonly enforced rules. Other policies and functionality to automate funding of incoming channels may be introduced in the future.