-
Notifications
You must be signed in to change notification settings - Fork 408
Add option accept or reject channel requests #1281
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
Add option accept or reject channel requests #1281
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1281 +/- ##
==========================================
- Coverage 90.50% 90.48% -0.02%
==========================================
Files 71 71
Lines 39042 39177 +135
==========================================
+ Hits 35336 35451 +115
- Misses 3706 3726 +20
Continue to review full report at Codecov.
|
lightning/src/ln/channelmanager.rs
Outdated
return self.internal_create_requested_channel(counterparty_node_id, their_features, msg); | ||
} | ||
|
||
fn internal_create_requested_channel(&self, counterparty_node_id: &PublicKey, their_features: InitFeatures, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal>{ |
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.
Instead of splitting the function here, we can simplify things a bit by splitting the function a few lines down and moving only the SendAcceptChannel
message generation out. There's no harm in having a channel be inserted into the channel_state.by_id
map even if its not accepted yet, we just have to make sure we reject a FundingCreated
message in Channel::funding_created
if the sender is trying to be too clever and skip waiting for our accept. This will require a new flag in the Channel
which is updated when we (eventually) call get_accept_channel
and checked in funding_created
.
From there, Event::OpenChannelRequest
can be tweaked to just include relevant info instead of doing it via a struct, and respond_to_open_channel_request
can just take the temporary_channel_id
. All that said, I'd suggest we err on the side of including too much data rather than too little, as the node operator may need extra data to decide if they want to accept a channel.
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.
Thanks a lot for the detailed input! I'll start working on implementing your suggestions.
Just to clarify though, how much/which data is enough for node operator to aid them in the decision to accept or reject the channel? Including all fields in the OpenChannel
msg is too excessive, but given that I'd really appreciate if I'd could get some feedback on which fields should be included instead of selecting myself.
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'm not sure there's necessarily a clear answer, but maybe include, for now (we can always add more later): counterparty node id, chain_hash, temporary_channel_id, funding_satoshis, push_msat?
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.
Thanks, I'll start with those.
lightning/src/util/events.rs
Outdated
@@ -515,6 +535,12 @@ impl Writeable for Event { | |||
(2, payment_hash, required), | |||
}) | |||
}, | |||
&Event::OpenChannelRequest { ref open_channel_request_info } => { | |||
11u8.write(writer)?; |
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.
11 is already used for DiscardFunding
. We need a new value here. That said, we shouldn't actually ever load this object from disk, similar to how we handle PendingHTLCsForwardable
and FundingGenerationReady
- if we have such an object when we go to serialize, it won't make sense when we go to reload it. In lightning, if a channel has not exchanged funding messages, it is dropped on reconnect (ie restart), so the peer will have forgotten about the channel entirely anyway.
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.
Thanks for the feedback! I'll make sure to fix that.
I've now updated the PR to hopefully resolve the issues raised in the feedback. I can of course squash the 2 commits into 1 if that's more suitable. |
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.
Basically looks good.
lightning/src/util/events.rs
Outdated
@@ -515,6 +540,11 @@ impl Writeable for Event { | |||
(2, payment_hash, required), | |||
}) | |||
}, | |||
&Event::OpenChannelRequest { .. } => { | |||
16u8.write(writer)?; |
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 needs to be odd - our read behavior is "even, and we dont understand it -> assume we cant read anything and it is an important event, refuse to deserialize at all", but here its an unimportant (so unimportant we want to throw it away) event, so we should use an odd value to indicate that. We should also add a comment on the read-side code noting that the value we use is used for OpenChannelRequest
(maybe a match branch).
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.
Thanks again for the detailed input! I'll assign it to 17 instead.
lightning/src/util/events.rs
Outdated
chain_hash: BlockHash, | ||
/// The channel value of the requested channel. | ||
funding_satoshis: u64, | ||
/// The amount to push to the counterparty if the channel request is accepted, in milli-satoshi. |
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.
That's us! Maybe say something like "the amount the counterparty will give us if the channel is opened" or talk about it as "our starting balance"
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.
Oh my bad, should have known that!
lightning/src/ln/channelmanager.rs
Outdated
/// The `temporary_channel_id` parameter indicates which channel the reponse is for. | ||
/// | ||
/// [`events::Event::OpenChannelRequest`]: crate::util::events::Event::OpenChannelRequest | ||
pub fn respond_to_open_channel_request(&self, accept_channel: bool, temporary_channel_id: [u8; 32]) -> Result<(), APIError> { |
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.
nit: I'd kinda prefer an API of accept_inbound_channel
with users instead calling force_close_channel
to reject the channel, that way our code stays consistent and we use the same codepaths for everything.
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.
That makes a lot of sense! I'll change to that.
lightning/src/ln/channelmanager.rs
Outdated
pub fn respond_to_open_channel_request(&self, accept_channel: bool, temporary_channel_id: [u8; 32]) -> Result<(), APIError> { | ||
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier); | ||
|
||
if let Some(counterparty_node_id) = self.internal_get_counterparty_node_id(temporary_channel_id) { |
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 is fundamentally race-y - you take the lock in internal_get_counterparty_node_id
, check if the channel is there, and then release the lock, then go into accept_requested_channel
and take the lock again. Anyway, this will be easy to remove with the above suggestion.
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.
Thanks, I'll fix it through the above suggestion.
b4d14ae
to
8d20adc
Compare
Updated the PR once more, to address the latest feedback. Also squashed all commits as they were becoming unfocused. |
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.
LGTM. Could really use a test (eg take a look at some of the simpler functional tests in lightning/src/ln/functional_tests.rs
), but if you don't have time to get around to that I'll be happy to take a look.
@@ -305,6 +305,9 @@ pub struct UserConfig { | |||
/// If this is set to false, we do not accept inbound requests to open a new channel. | |||
/// Default value: true. | |||
pub accept_inbound_channels: bool, | |||
/// If this is set to true, the user needs to manually accept inbound requests to open a new channel. | |||
/// Default value: false. |
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.
nit: Would be good to at least link to Event::OpenChannelRequest
here.
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.
Sure, I'll add that.
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.
One question about a field but otherwise ACK with testing either here or in follow-up
lightning/src/util/events.rs
Outdated
/// The genesis hash of the blockchain where the channel is requested to be opened. | ||
chain_hash: BlockHash, |
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 wonder if this is a useful field? It seems a bit extraneous to me
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.
Yea, I guess not, we don't currently support multi-chain operation so the chain hash has to match what we are on anyway. ie its always the same value by the time it gets here. I'd say remove it.
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.
Great ok, I'll remove the field.
lightning/src/ln/channel.rs
Outdated
@@ -1918,6 +1933,10 @@ impl<Signer: Sign> Channel<Signer> { | |||
// channel. | |||
return Err(ChannelError::Close("Received funding_created after we got the channel!".to_owned())); | |||
} | |||
if self.inbound_awaiting_accept { | |||
// The Channel must manually accepted before the FundingCreated is received. |
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.
nit: must *be manually accepted
I think we can get rid of this comment though
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 agree, I'll get rid of it.
lightning/src/ln/channel.rs
Outdated
@@ -536,6 +536,17 @@ pub(super) struct Channel<Signer: Sign> { | |||
#[cfg(not(test))] | |||
closing_fee_limits: Option<(u64, u64)>, | |||
|
|||
/// Flag that ensures that the `get_accept_channel` function must be called before the | |||
/// `funding_created` function is executed successfully. The reason for need of this flag is |
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.
nit: s/need of//
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.
Thanks!
Great, thanks a lot to both of you! Sure I'll look into implementing some tests. Unfortunately I've got quite much in the upcoming days, but I'll try to get it done during weekend. I could also look into implementing support for the feature in the ldk-sample repo afterwards if that's helpful. |
No rush at all. If you have the time to address the other comments and squash the commits here, that'd be appreciated too. I'm working on 0conf support which will likely be based on this, so I may just write a test for you and we can merge it without, depending on timing. |
8d20adc
to
f38f2d5
Compare
Ok sounds great! Just pushed the suggested changes. |
f38f2d5
to
8c30b59
Compare
Pushed some tests of the feature if you haven't had time to create some already. I made one test for accepting an inbound request, and one for rejecting a request. I also wanted to make a test for the case where the counterparty node tries to be smart and send a I pushed the tests in a separate commit, but I can of course squash them if that's more suitable. |
Nice! Those tests look great. Indeed, it'd be nice to see the channel get closed if the counterparty sends a |
Thanks! Great, thanks for that info. |
Just pushed a draft of the test that rejects the msg before the channel was manually accepted. I'm not really satisfied with the solution though, so if I've misunderstood how to test the case, or if there's a simpler way to do it please let me know. The key issue with my solution is that I need to extract the All of this is done, just for the purpose of generating the funding transaction for If I've completely misunderstood the flow, or if there's any simpler way to generate the funding transaction that requires less prerequisites, I'd be really thankful for that feedback! |
lightning/src/ln/functional_tests.rs
Outdated
// function, which is required in order for the create_funding_transaction function not to | ||
// crash when nodes[0] is passed to it. | ||
{ | ||
let mut channel_state_lock = nodes[1].node.channel_state.lock().unwrap(); |
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.
Note you can use the get_channel_ref
macro here to do most of the work.
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.
Great thanks! Hadn't found that one.
lightning/src/ln/channel.rs
Outdated
self.inbound_awaiting_accept | ||
} | ||
|
||
pub fn set_is_awaiting_accept(&mut self) { |
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 is generally fine with me, actually, but we should make this #[cfg(test)]
. An alternative way to accomplish the same test would be to split get_accept_channel
into an utility to get the message itself and another pub method to get the message while setting the awaiting flag.
df4c3dc
to
5b739eb
Compare
Thanks for the feedback! Pushed some changes to address it. I chose to split Also added two more test I thought of related to the manually accepting of inbound channels feature. |
5b739eb
to
6517c62
Compare
Fixed crate error. My bad! |
6517c62
to
dbe587c
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.
Testing looks super solid! Just nits here, if no further feedback I think it'd be fine to just merge
lightning/src/ln/functional_tests.rs
Outdated
// Get the [`AcceptChannel`] message of [`nodes[1]`] without calling the | ||
// [`ChannelManager::accept_inbound_channel`] function, which generates the | ||
// [`MessageSendEvent::SendAcceptChannel`] event. This is passed to [`nodes[0]`] | ||
// [`handle_accept_channel`] function, which is required in order for the | ||
// [`create_funding_transaction`] function to succeed when [`nodes[0]`] is passed to it. |
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.
Can remove the surrounding braces from all of these and elsewhere in the tests, I think they only have meaning when used in docs =]
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.
Oh, I was quite unsure how to deal with those. Thanks a lot for clarifying!
lightning/src/ln/channelmanager.rs
Outdated
@@ -4101,6 +4101,34 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana | |||
} | |||
} | |||
|
|||
/// Called to accept a request to open a channel after the | |||
/// [`events::Event::OpenChannelRequest`] has been triggered. |
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.
nit: s/[events::Event::OpenChannelRequest
]/[Event::OpenChannelRequest
] + link update
lightning/src/ln/channel.rs
Outdated
@@ -536,6 +536,17 @@ pub(super) struct Channel<Signer: Sign> { | |||
#[cfg(not(test))] | |||
closing_fee_limits: Option<(u64, u64)>, | |||
|
|||
/// Flag that ensures that the `get_accept_channel` function must be called before the | |||
/// `funding_created` function is executed successfully. The reason for this flag is that | |||
/// when the util::config::UserConfig.manually_accept_inbound_channels is set to true, |
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.
nit: s/util::config::UserConfig.manually_accept_inbound_channels/UserConfig::manually_accept_inbound_channels
lightning/src/ln/channel.rs
Outdated
/// Flag that ensures that the `accept_inbound_channel` function must be called before the | ||
/// `funding_created` function is executed successfully. The reason for this flag is that |
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.
nit: s/the accept_inbound_channel
function/accept_inbound_channel
and similar for funding_created
and elsewhere
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.
Makes sense, thanks!
lightning/src/ln/channel.rs
Outdated
|
||
self.inbound_awaiting_accept = false; | ||
|
||
return self.get_accept_channel_message(); |
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.
nit: s/return self.get_accept_channel_message();/self.get_accept_channel_message()
lightning/src/ln/channel.rs
Outdated
/// [`Channel::accept_inbound_channel`] function instead. | ||
/// | ||
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel | ||
pub fn get_accept_channel_message(&self) -> msgs::AcceptChannel { |
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.
Don't think it matters too much but we could make this pub just in testing
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.
Yea, I'd strongly prefer this be a private method with a #[cfg(test)]
method that exposes it just for testing.
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.
Ok sure, I'll make it private and expose a function for testing!
Needs rebase, sorry about that. |
Add a new config flag `UserConfig::manually_accept_inbound_channels`, which when set to true allows the node operator to accept or reject new channel requests. When set to true, `Event::OpenChannelRequest` will be triggered once a request to open a new inbound channel is received. When accepting the request, `ChannelManager::accept_inbound_channel` should be called. Rejecting the request is done through `ChannelManager::force_close_channel`.
Add functional tests for manually responding to inbound channel requests. Responding to inbound channel requests are required when the `manually_accept_inbound_channels` config flag is set to true. The tests cover the following cases: * Accepting an inbound channel request * Rejecting an inbound channel request * FundingCreated message sent by the counterparty before accepting the inbound channel request * Attempting to accept an inbound channel request twice * Attempting to accept an unkown inbound channel
dbe587c
to
1891b37
Compare
Thanks again for all the feedback! Just pushed some changes which I hope addresses all of it. |
Adds support for manually accepting or rejecting a request to open a channel. Issue #1242