-
Notifications
You must be signed in to change notification settings - Fork 404
Exchange splice_locked
messages
#3741
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
base: main
Are you sure you want to change the base?
Conversation
👋 Thanks for assigning @wpaulino as a reviewer! |
The logic around determining if the |
When processing confirmed transactions and updates to the best block, ChannelManager may be instructed to send a channel_ready message when a channel's funding transaction has confirmed and has met the required number of confirmations. A similar action is needed for sending splice_locked once splice transaction has confirmed with required number of confirmations. Generalize do_chain_event signature to allow for either scenario.
When processing confirmed transactions, if the funding transaction is found then information about it in the ChannelContext is updated. In preparation for splicing, move this data to FundingScope.
dfbc04e
to
e4c0566
Compare
@wpaulino Ok, this is in better shape for a high-level look. I don't believe it correctly handles unconfirmed splice transactions yet. Also, doesn't yet re-send |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3741 +/- ##
==========================================
+ Coverage 89.10% 90.34% +1.24%
==========================================
Files 156 158 +2
Lines 123431 135603 +12172
Branches 123431 135603 +12172
==========================================
+ Hits 109985 122515 +12530
+ Misses 10760 10568 -192
+ Partials 2686 2520 -166 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
🔔 1st Reminder Hey @wpaulino! This PR has been waiting for your review. |
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. The preparational changes are very clear. The WIP part also makes sense so far.
🔔 2nd Reminder Hey @wpaulino! This PR has been waiting for your review. |
lightning/src/ln/channel.rs
Outdated
|
||
match pending_splice.sent_funding_txid { | ||
Some(sent_funding_txid) if confirmed_funding_txid == sent_funding_txid => { | ||
debug_assert!(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.
We may need to replay splice_locked
if a disconnect happened before they were able to process it. Unclear if we'd want to use this same code path for it or not.
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.
By this do you mean for channel_reestablish
?
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, I assume there is a similar retransmission case we need to handle there, like with channel_ready
.
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.
Gonna leave this for a follow-up, if that's ok.
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, probably better to wait for #3637 to land anyway.
e4c0566
to
49f8ef6
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.
Addressed most comments other than adding an event and for re-sending splice_locked
. See comment replies for open questions.
Also, added code to insert the new scid in short_to_chan_info
. Should we remove the old one?
lightning/src/ln/channel.rs
Outdated
|
||
match pending_splice.sent_funding_txid { | ||
Some(sent_funding_txid) if confirmed_funding_txid == sent_funding_txid => { | ||
debug_assert!(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.
By this do you mean for channel_reestablish
?
ef048e6
to
f3b0989
Compare
Squashed fixups |
An offline discussion we had around |
lightning/src/ln/channelmanager.rs
Outdated
@@ -3026,7 +3026,7 @@ macro_rules! locked_close_channel { | |||
// into the map (which prevents the `PeerState` from being cleaned up) for channels that | |||
// never even got confirmations (which would open us up to DoS attacks). | |||
let update_id = $channel_context.get_latest_monitor_update_id(); | |||
if $channel_context.get_funding_tx_confirmation_height().is_some() || $channel_context.minimum_depth() == Some(0) || update_id > 1 { | |||
if $channel_funding.get_funding_tx_confirmation_height().is_some() || $channel_context.minimum_depth() == Some(0) || update_id > 1 { |
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 thought we agreed to try to keep the concept of funding scopes outside of ChannelManager
? I think for this we can move to a is_funding_confirmed_or_0conf
call or something?
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 macro doesn't have access to the channel, only the context which doesn't have reference to the funding scope. So it would require much more re-work than I'd like to do in this PR.
Instead, I'd rather make a separate PR after all the changes needed for FundingScope
are complete. Hopefully in a couple PRs.
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, also forgot to drop these two commits since one reverts the previous one. But the general idea still stands for other occurrences.
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.
Tried to avoid this but the problem is that locked_close_channel
is called throughout the file including by convert_channel_err
, which likewise is called throughout. Additionally, convert_channel_err
has a rule that expects a FundedChannel
so that it can pass it to get_channel_update_for_broadcast
.
Might be a way to refactor this but I think it should wait for a follow-up given it's not going to be straightforward.
lightning/src/ln/channelmanager.rs
Outdated
@@ -11639,7 +11639,7 @@ where | |||
for chan in peer_state.channel_by_id.values().filter_map(Channel::as_funded) { | |||
let txid_opt = chan.funding.get_funding_txo(); | |||
let height_opt = chan.context.get_funding_tx_confirmation_height(); | |||
let hash_opt = chan.context.get_funding_tx_confirmed_in(); | |||
let hash_opt = chan.funding.get_funding_tx_confirmed_in(); |
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 we avoid new references to Channel::funding
in ChannelManager
? I thought we wanted to remove 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.
I was able to get rid of this one by moving get_funding_tx_confirmed_in
to FundedChannel
since this is the only use.
@@ -3031,7 +3031,7 @@ macro_rules! locked_close_channel { | |||
$peer_state.closed_channel_monitor_update_ids.insert(chan_id, update_id); | |||
} | |||
let mut short_to_chan_info = $self.short_to_chan_info.write().unwrap(); | |||
if let Some(short_id) = $channel_context.get_short_channel_id() { | |||
if let Some(short_id) = $channel_funding.get_short_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.
Same here, can we avoid this change?
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.
Similarly, we'd need this to take a Channel
instead of a ChannelContext
, but the problem is that convert_channel_err
needs a FundedChannel
for one rule as mentioned in another comment. Maybe we eventually just add any methods called from those macros on both Channel
and each sub-struct so that it can be used either way?
Separate but related to this, I'm wondering now which Currently, we use the pre-splice
After that So in the scenario described above, should we transition to the pending Then that way for Related discussion: #3592 (comment) |
When processing confirmed transactions, if the funding transaction is found then information about it in the ChannelContext is updated. In preparation for splicing, move this data to FundingScope.
When processing confirmed transactions, if the funding transaction is found then information about it in the ChannelContext is updated. In preparation for splicing, move this data to FundingScope.
When checking if channel_ready should be sent, the funding transaction must reach minimum_depth confirmations. The same logic is needed for splicing a channel, so refactor it into a helper method.
f3b0989
to
bd1a788
Compare
Discussed offline with @TheBlueMatt and @wpaulino. The two scenarios are closing while funding negotiation takes place and while waiting for the splice to confirm. For the latter, it would be better to a have general approach in For the former, we won't have a |
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 think i responded to all the active discussions
lightning/src/ln/channel.rs
Outdated
} | ||
|
||
let funding_tx_confirmations = height as i64 - funding.funding_tx_confirmation_height as i64 + 1; | ||
if funding_tx_confirmations < minimum_depth.unwrap_or(0) as i64 { |
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 do kinda wonder if we want to reuse the channel-open minimum_depth
for splice lock-in. For channel opens the user can always set the minimum_depth
by overriding the config in the inbound manual-accept pipeline or by overriding the config in the outbound open init. I'm not entirely sure a user will want to override the minimum_depth for a splice, but if eg they overrode it for a channel open to set it lower cause the channel was low value suddenly a splice would increase their risk which they didn't intend. Maybe we can move the min-depth setting into the live channel config so users can update it? Either way docs for the min-depth setting should be updated to note it captures splices.
The minimum_depth of a channel is overridden to COINBASE_MATURITY if the funding transaction is the coinbase transaction. However, if this is to be reused for a splice's minimum_depth, it would be a problem since sending splice_locked would be unnecessarily delayed. Now that FundingScope contains the funding transaction, use this to check if it is a coinbase transaction instead of overriding minimum_depth.
FundingScope::funding_tx_confirmation_height is reset as part of calling ChannelContext::check_funding_meets_minimum_depth via FundedChannel::check_get_channel_ready. This side effect requires using mutable references to self when otherwise it would not be needed. Instead of reseting funding_tx_confirmation_height there, do so when unconfirming the funding transaction.
0-conf channels always meet the funding minimum depth once accepted. Special case this in check_funding_meets_minimum_depth such that it isn't implicit in later calculations. Since a minimum depth is always set when the channel is accepted, expect this to be the case in the method since it should only be called on a ChannelContext in a FundedChannel.
When transactions confirm or the best block is updated, check if any pending splice funding transactions have confirmed to an acceptable depth. If so, send a splice_locked message to the counterparty and -- if the counterparty has exchanged a splice_locked message for the same funding txid -- promote the corresponding FundingScope such that the new funding can be utilized.
bd6ceea
to
d72d8b5
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.
More comments addressed along with some still unresolved needing feedback. Getting closer...
// time we saw and it will be ignored. | ||
let best_time = self.context.update_time_counter; | ||
|
||
funding.funding_tx_confirmation_height = 0; |
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.
Doing so causes some reorg tests to fail. I can avoid some failures by moving the self.funding.funding_tx_confirmed_in
reset after the call to do_best_block_updated
as it is used in there. But doing the same for self.funding.short_channel_id
causes other failures. Specifically, short_to_chan_info
is not cleared.
lightning/src/ln/channel.rs
Outdated
.map(|tx| tx.is_coinbase()) | ||
.unwrap_or(false); | ||
|
||
let minimum_depth = { |
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.
@wpaulino Requested it in #3741 (comment). An earlier version moved minimum_depth
to FundingScope
because otherwise we would use COINBASE_MATURITY
for splices of channels established with a coinbase transaction. But this resulted in needing to still keep around the original minimum_depth
in ChannelContext
. The workaround was to keep minimum_depth
in ChannelContext
and have a special case here for the coinbase transaction.
lightning/src/ln/channel.rs
Outdated
}; | ||
|
||
match pending_splice.sent_funding_txid { | ||
Some(sent_funding_txid) if confirmed_funding_txid == sent_funding_txid => { |
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.
Hmmm... we could do that but FundingScope
is also used for establishment and hangs around once the splice is locked. So the additional field isn't meaningful then. Maybe it doesn't matter?
Just hate to have a field that isn't needed (or only needed) after a certain point. That's kinda the situation with ChannelContext
where we have Option
fields that should always be Some
.
We'd also need to unset the bool in every other FundingScope
if the counterparty sends splice_locked
again with a different funding_txid
. Seem kinda fragile as we need to maintain an invariant that the bool is true for at most one FundingScope
in the list.
lightning/src/ln/channel.rs
Outdated
@@ -4851,7 +4851,24 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider { | |||
} | |||
|
|||
fn check_funding_confirmations(&self, funding: &mut FundingScope, height: u32) -> bool { | |||
if funding.funding_tx_confirmation_height == 0 && self.minimum_depth != Some(0) { | |||
let is_coinbase = funding |
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.
We'd need to pass in the appropriate minimum_depth
at each call site, which is kinda meh.
return Ok(self.get_announcement_sigs(node_signer, chain_hash, user_config, best_block.height, logger)); | ||
} | ||
|
||
// TODO: Close 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.
Hmmm... docs indicate that that is for when the user calls ChannelManager::force_close_channel
.
lightning/src/ln/channelmanager.rs
Outdated
let persist = match &res { | ||
Err(e) if e.closes_channel() => NotifyOption::DoPersist, | ||
Err(_) => NotifyOption::SkipPersistHandleEvents, | ||
Ok(()) => NotifyOption::SkipPersistHandleEvents, |
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.
Updated to persist when returning OK as discussed offline.
lightning/src/ln/channel.rs
Outdated
let funding_tx_confirmations = height as i64 - funding.funding_tx_confirmation_height as i64 + 1; | ||
if funding_tx_confirmations <= 0 { | ||
funding.funding_tx_confirmation_height = 0; | ||
} |
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.
Renamed to check_funding_meets_minimum_depth
and made a separate commit to special case 0-conf.
This method is only applicable for FundedChannel, so it shouldn't be accessible from ChannelContext.
Now that ChannelContext::minimum_depth is not overridden with COINBASE_MATURITY when the funding transaction is the coinbase transaction, so do instead in the identically named method. Also, add a minimum_depth to Channel. The one on ChannelContext can become private once FudningScope doesn't need to be accessed directly from a ChannelManager macro. This fixes ChannelDetails showing an incorrect minimum depth when the coinbase transaction is used to funded the channel.
When a splice funding transaction is unconfirmed, update the corresponding FundingScope just as is done when the initial funding transaction is unconfirmed.
Pending funding transactions for splices should be monitored for appearance on chain. Include these in ChannelManager::get_relevant_txids so that they can be watched.
Once both parties have exchanged splice_locked messages, the splice funding is ready for use. Emit an event to the user indicating as much.
A ChannelReady event is used for both channel establishment and splicing to indicate that the funding transaction is confirmed to an acceptable depth and thus the channel can be used with the funding. An upcoming SplicePending event will be emitted for each pending splice (i.e., both the initial splice attempt and any RBF attempts). Thus, when a ChannelReady event is emitted, the funding_txo must be included to differentiate between which ChannelPending -- which also contains the funding_txo -- that the event corresponds to.
d72d8b5
to
66fa294
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.
Most comments should be addressed now but will need responses on the following comments:
} | ||
} | ||
|
||
self.context.check_for_funding_tx_spent(&self.funding, tx, logger)?; |
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.
Resolved in an earlier fixup (9b2b24b).
lightning/src/ln/channel.rs
Outdated
let mut confirmed_funding = None; | ||
#[cfg(splicing)] | ||
for funding in self.pending_funding.iter_mut() { | ||
if confirmed_funding.is_some() { |
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.
Fixed in 8efe7c9.
}, | ||
}; | ||
|
||
Err(MsgHandleErrInternal::send_err_msg_no_close("TODO(splicing): Splicing is not implemented (splice_locked)".to_owned(), msg.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.
I guess we may as well return Ok
given we are enqueuing messages and events? This was copied from the other handlers.
lightning/src/ln/channel.rs
Outdated
.map(|tx| tx.is_coinbase()) | ||
.unwrap_or(false); | ||
|
||
let minimum_depth = { |
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.
Added a commit to make minimum_depth
accurate in ChannelDetails
.
lightning/src/ln/channel.rs
Outdated
|
||
#[cfg(splicing)] | ||
fn check_get_splice_locked( | ||
&mut self, pending_splice: &PendingSplice, funding: &mut FundingScope, height: u32, |
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, I figured as much. Will wait until all other comments are addressed before seeing to this. Not quite sure the added complexity would be worth it.
Went ahead with tracking the index instead of holding a mutable reference and moved the appropriate methods to FundedChannel
.
After a splice has been negotiated, each party must send a
splice_locked
message to the other party once the splice transaction has had an acceptable number of confirmations. Update the logic for processing newly confirmed transactions and updated best block to sendsplice_locked
when appropriate.Likewise, handle
splice_locked
and promote the channel'sFundingScope
once bothsplice_locked
messages have been exchanged.