Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Encapsulate `Channel` enum variants inside a struct by jkczyz · Pull Request #3550 · lightningdevkit/rust-lightning · GitHub
Skip to content

Encapsulate Channel enum variants inside a struct - #3550

Merged
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase
Jan 27, 2025
Merged

Encapsulate Channel enum variants inside a struct#3550
TheBlueMatt merged 13 commits into
lightningdevkit:mainfrom
jkczyz:2025-01-refactor-channel-phase

Conversation

@jkczyz

@jkczyzjkczyz commented Jan 17, 2025

Copy link
Copy Markdown
Contributor

Instead of exposing the Channel enum variants, make a Channel struct that wraps a ChannelPhase enum. This allows updating a Channel's phase without consuming it, which isn't possible when it is in a map without removing the entry first. Then move phase transitions can from ChannelManager to Channel. This allows for simpler logic in ChannelManager since the channel does not need to removed and then re-added into the channel_by_id map during a phase transition (or failed one).

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from effabbb to 9773f1aCompareJanuary 17, 2025 23:21

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good (so far)

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyzjkczyz added weekly goal Someone wants to land this this week and removed weekly goal Someone wants to land this this week labels Jan 21, 2025
@jkczyz

jkczyz commented Jan 21, 2025

Copy link
Copy Markdown
ContributorAuthor

Ok, AFAICT, the PR as-is should have changed all the possible phase transitions where we were removing and re-inserting into a map (except when going from a temporary channel id). Reviewers, please check that this is the case by looking at the commits introducing From trait implementations in #3513.

FYI, the changes in the last commit may interfere with #3423.

@jkczyz
jkczyz marked this pull request as ready for review January 21, 2025 19:49
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines -8165 to -8189
self.chain_monitor
.watch_channel(funded_chan.context.get_funding_txo().unwrap(), monitor)
.map_err(|()| {
// We weren't able to watch the channel to begin with, so no
// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info(msg.channel_id);
return Err(convert_channel_err!(self, peer_state, e, chan, &msg.channel_id, FUNDED_CHANNEL).1);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little confused by this comment given the earlier version removed the entry from the map, and this new version uses try_channel_entry to remove it on error below. i.e., Why do we need to call unset_funding_info if the channel is no longer in the map?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to call it in cases where the new channel conflicts with an existing channel. When locked_close_channel eventually gets called on the new channel, it needs to have its funding info removed, otherwise we'll remove the mapping in outpoint_to_peer for the original channel, which is crucial for its handling of MonitorEvents. If we pursue #3554 all the way, that map can finally be removed.

@jkczyzjkczyz added the weekly goal Someone wants to land this this week label Jan 21, 2025

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other cases where I'd imagine a phase transition happens:

  • Failed splice negotiation on an already funded channel: not yet implemented, OK for now
  • Transaction reorg after confirmation: turns out we just force close anyway, and we don't transition back to unfunded regardless of the changes proposed here

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 9773f1a to f3cd992CompareJanuary 22, 2025 17:59
@codecov

codecovBot commented Jan 22, 2025

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 71.69043% with 139 lines in your changes missing coverage. Please review.

Project coverage is 89.54%. Comparing base (4579e63) to head (f3cd992).
Report is 83 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/ln/channel.rs50.34%69 Missing and 3 partials ⚠️
lightning/src/ln/channelmanager.rs79.93%58 Missing and 7 partials ⚠️
lightning/src/ln/functional_tests.rs88.23%1 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #3550 +/- ##
==========================================
+ Coverage 88.57% 89.54% +0.96% 
==========================================
Files 149 149 Lines 114539 122358 +7819 Branches 114539 122358 +7819 ==========================================
+ Hits 101449 109561 +8112 + Misses 10602 10370 -232 + Partials 2488 2427 -61 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f3cd992 to e84d9d1CompareJanuary 23, 2025 18:31
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from e84d9d1 to f7f5567CompareJanuary 23, 2025 20:13

@wpaulinowpaulino left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after squash

Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from f7f5567 to 4a30d10CompareJanuary 23, 2025 22:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

LGTM after squash

@optout21 Let me know if you'd like to me to squash the fixups

@carlaKCcarlaKC left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New to the codebase so comments are all non-blocking, nice refactor!

Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 4a30d10 to 22436bbCompareJanuary 24, 2025 16:37
optout21
optout21 previously approved these changes Jan 24, 2025

@optout21optout21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, OK to squash

@jkczyz
jkczyzforce-pushed the 2025-01-refactor-channel-phase branch from 22436bb to 6639f0cCompareJanuary 24, 2025 23:05
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Squashed. Looks like I need to rebase.

Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
Now that ChannelPhase has been renamed, drop phase from related
identifiers.
The old ChannelPhase variants will be used internally in Channel, so
they should no longer be used elsewhere.
Now that ChannelPhase has been renamed, drop phase from related
identifiers. Also, qualify uses of chan to avoid overloading the
identifier.
Instead of exposing the Channel enum variants, make a Channel struct
that wraps a ChannelPhase enum. This allows updating a Channel's phase
without consuming it, which isn't possible when it is in a map without
removing the entry first (e.g., as is done in ChannelManager).
When attempting a ChannelPhase transition, the variant-specific channel
struct needs to be taken by self in order to move its ChannelContext
into the struct for the new phase. Add a variant for an intermediate
state, allowing such actions.
When moving ChannelPhase logic from ChannelManager into Channel, it is
useful to error when a Channel is not in the expected state. Add a
ChannelError::SendError variant for this purpose, which results in
sending an error message without closing the channel.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the funding_signed phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then readded into the
channel_by_id map.
Now that ChannelPhase is encapsulated in Channel, phase transitions can
be moved from ChannelManager to Channel. Update the tx_complete phase
transition accordingly. This allows for simpler logic in ChannelManager
since the channel does not need to removed and then re-added into the
channel_by_id map.
@jkczyz

Copy link
Copy Markdown
ContributorAuthor

Rebased.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

/// its variants containing an appropriate channel struct.
pub(super) enum Channel<SP: Deref> where SP::Target: SignerProvider {
enum ChannelPhase<SP: Deref> where SP::Target: SignerProvider {
Undefined,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleh, I almost prefer unsafe { mem::uninitialized }, oh well.

hash_map::Entry::Occupied(mut chan_entry) => {
let chan = chan_entry.get_mut();
match chan
.funding_signed(&msg, best_block, &self.signer_provider, &self.logger)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to standardize whether wrapping the logger happens in channelmanager or channel and make sure we're consistent...at some point

// updates should be made on it. Previously, full_stack_target
// found an (unreachable) panic when the monitor update contained
// within `shutdown_finish` was applied.
chan.unset_funding_info();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We removed debug_assert!(matches!(e, ChannelError::Close(_)) which I think is actually important here since we don't re-add the channel.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be ChannelError::SendError if the channel wasn't in the expected phase.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err, right, duh, we're no longer removing-and-adding so this is fine.

@TheBlueMatt
TheBlueMatt merged commit ed7befc into lightningdevkit:mainJan 27, 2025
@jkczyzjkczyz mentioned this pull request Jan 29, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jkczyz@TheBlueMatt@wpaulino@optout21@carlaKC