') + ')', '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('^' + ".*" + ', '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" + ', '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('^' + ".*" + ', '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); } })(); })(); Wait to create a channel until after accepting. by waterson · Pull Request #2428 · lightningdevkit/rust-lightning · GitHub
Skip to content

Wait to create a channel until after accepting. - #2428

Merged
TheBlueMatt merged 1 commit into
lightningdevkit:mainfrom
waterson:create-channel-after-accept
Aug 15, 2023
Merged

Wait to create a channel until after accepting.#2428
TheBlueMatt merged 1 commit into
lightningdevkit:mainfrom
waterson:create-channel-after-accept

Conversation

@waterson

Copy link
Copy Markdown
Contributor

Create a new table in 'peer_state' to maintain unaccepted inbound channels; i.e., a channel for which we've received an 'open_channel' message but that user code has not yet confirmed for acceptance. When user code accepts the channel (e.g. via 'accept_inbound_channel'), create the channel object and as before.

Currently, the 'open_channel' message eagerly creates an InboundV1Channel object before determining if the channel should be accepted. Because this happens /before/ the channel has been assigned a user identity (which happens in the handler for OpenChannelRequest), the channel is assigned a random user identity. As part of the creation process, the channel's cryptographic material is initialized, which then uses this randomly generated value for the user's channel identity e.g. in SignerProvider::generate_channel_keys_id.

By delaying the creation of the InboundV1Channel until /after/ the channel has been accepted, we ensure that we defer cryptographic initialization until we have given the user the opportunity to assign an identity to the channel.

@dunxen

Copy link
Copy Markdown
Contributor

We're looking at actually reducing the maps we create and going with an enum approach and single map for channels #2422, so this might make sense as an AwaitingAccept variant.

Thanks for bringing this up. We could discuss on this PR, but I think an issue would be better.

@waterson

Copy link
Copy Markdown
ContributorAuthor

Sounds good. I made some changes to get the tests to pass; would be interested in discussing those. Let me update the PR.

@codecov-commenter

codecov-commenter commented Jul 20, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 96.26% and project coverage change: -0.04%⚠️

Comparison is base (131560e) 90.35% compared to head (2888f76) 90.32%.

❗ Current head 2888f76 differs from pull request most recent head 0184727. Consider uploading reports for the commit 0184727 to get more accurate results

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@ Coverage Diff @@## main #2428 +/- ##
==========================================
- Coverage 90.35% 90.32% -0.04% 
==========================================
Files 106 106 Lines 56242 56232 -10 Branches 56242 56232 -10 ==========================================
- Hits 50816 50789 -27 - Misses 5426 5443 +17 
Files ChangedCoverage Δ
lightning/src/events/mod.rs42.51% <ø> (ø)
lightning/src/ln/functional_tests.rs98.17% <75.00%> (-0.06%)⬇️
lightning/src/ln/channelmanager.rs85.61% <97.50%> (-0.07%)⬇️
lightning/src/ln/channel.rs89.48% <100.00%> (+0.02%)⬆️
lightning/src/ln/shutdown_tests.rs98.45% <100.00%> (ø)

... and 2 files with indirect coverage changes

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

@dunxen
dunxen self-requested a review July 20, 2023 19:01

@dunxendunxen 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.

Thanks this is looking like the right direction. I need to do some more review of what’s moved around but this looks good.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/functional_tests.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Oof, indeed, nice catch. Looks like this needs a small rebase, sorry about that.

@waterson
watersonforce-pushed the create-channel-after-accept branch from 8e79049 to 96f52f5CompareJuly 31, 2023 16:58
@waterson
waterson requested a review from dunxenJuly 31, 2023 17:58
@waterson
watersonforce-pushed the create-channel-after-accept branch from 41eb3b2 to ae0ce65CompareJuly 31, 2023 18:21

@alecchendevalecchendev 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 like rebase caught some extra commits :). Otherwise, LGTM besides one comment and a nit

Comment threadlightning/src/ln/shutdown_tests.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@waterson
watersonforce-pushed the create-channel-after-accept branch from ae0ce65 to 8411b57CompareJuly 31, 2023 19:25
@waterson

Copy link
Copy Markdown
ContributorAuthor

Thank you for the reviews! PTAL when you get a chance!

@dunxendunxen 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.

Looking good. I'm wondering if we can now do away with ChannelContext's inbound_awaiting_accept and InboundV1Channel::is_awaiting_accept()

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@dunxen

Copy link
Copy Markdown
Contributor

I'm wondering if we can now do away with ChannelContext's inbound_awaiting_accept and InboundV1Channel::is_awaiting_accept()

Actually I think we can punt this to a follow-up, but it would be nice to remove it if this PR makes it obsolete.

@waterson

Copy link
Copy Markdown
ContributorAuthor

@dunxen fwiw here is a patch that removes inbound_awaiting_accept. It compiles and passes tests. I can add it to the commit chain here if you think that makes sense,.

@dunxen

dunxen commented Aug 2, 2023

Copy link
Copy Markdown
Contributor

@dunxen fwiw here is a patch that removes inbound_awaiting_accept. It compiles and passes tests. I can add it to the commit chain here if you think that makes sense,.

Looks good! As for this comment, we can actually get rid of the InboundV1Channel::set_0conf() method entirely as we'll now know if we must set 0conf when invoking InboundV1Channel::new(), so I think we just need a field there like set_0conf: bool and then inside InboundV1Channel::new() we can then override the minimum_depth based on that. Then we must still keep the if !accept_0conf && channel.context.get_channel_type().requires_zero_conf() check.

We can do this since having an InboundV1Channel will always mean that it's not awaiting accept anymore, unless I'm mistaken?

EDIT: This also means we could probably get rid of the ChannelContext::inbound_awaiting_accept field entirely too. We don't use or serialize it anywhere else.

@waterson

Copy link
Copy Markdown
ContributorAuthor

@dunxen fwiw here is a patch that removes inbound_awaiting_accept. It compiles and passes tests. I can add it to the commit chain here if you think that makes sense,.

Looks good! As for this comment, we can actually get rid of the InboundV1Channel::set_0conf() method entirely as we'll now know if we must set 0conf when invoking InboundV1Channel::new(), so I think we just need a field there like set_0conf: bool and then inside InboundV1Channel::new() we can then override the minimum_depth based on that. Then we must still keep the if !accept_0conf && channel.context.get_channel_type().requires_zero_conf() check.

We can do this since having an InboundV1Channel will always mean that it's not awaiting accept anymore, unless I'm mistaken?

EDIT: This also means we could probably get rid of the ChannelContext::inbound_awaiting_accept field entirely too. We don't use or serialize it anywhere else.

So... I'm a bit worried about this exploding into a mega PR that will become increasingly difficult to review. Would you be comfortable to pursuing this cleanup in a follow-on?

@dunxen

Copy link
Copy Markdown
Contributor

So... I'm a bit worried about this exploding into a mega PR that will become increasingly difficult to review. Would you be comfortable to pursuing this cleanup in a follow-on?

Haha sure. I thought the PR blowing up might be the case 😄

@dunxen

Copy link
Copy Markdown
Contributor

Ok so I believe this looks good, and I think we can squash any fixups. We'll need another reviewer though

@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.

Feel free to squash before addressing my feedback.

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
@waterson
watersonforce-pushed the create-channel-after-accept branch from 0df5629 to b90f6c1CompareAugust 2, 2023 22:22
@waterson
waterson requested review from dunxen and wpaulinoAugust 2, 2023 23:18
@waterson

Copy link
Copy Markdown
ContributorAuthor

Thank you for the review @wpaulino! PTAL when you get a chance. Also a few unresolved that might need some advice... :)

Comment threadlightning/src/ln/channelmanager.rs Outdated
@dunxen

dunxen commented Aug 4, 2023

Copy link
Copy Markdown
Contributor

Oh hmm. I might have missed it but we'll need to make sure these requests get purged after some time like we do with inbound channels that are taking too long to finish handshake.

And probably on disconnecting too although maybe we can keep them and try when reconnected. Probably best to just drop them on disconnect for now.

EDIT: I don't see anything wrong with keeping them on disconnect so long as we still expire them after some time.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@dunxen

Copy link
Copy Markdown
Contributor

The CI failures look like we're just missing some use of the new parameter for InboundV1Channel::new in some tests.

Otherwise looks good for squash.

@waterson
watersonforce-pushed the create-channel-after-accept branch from 36cfb03 to da1bc11CompareAugust 9, 2023 15:40

@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 but still needs a squash on commits 8d00338, 30101b3, and 3a3ba4b. Also, please keep commit messages to 72 characters max per line.

Comment threadlightning/src/ln/functional_tests.rs Outdated
@waterson
watersonforce-pushed the create-channel-after-accept branch from 25c4aa1 to 4e4bec7CompareAugust 10, 2023 13:52
dunxen
dunxen previously approved these changes Aug 10, 2023
wpaulino
wpaulino previously approved these changes Aug 10, 2023
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, this needs a trivial rebase, sorry about that. Conceptually LGTM, tho.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@waterson
waterson dismissed stale reviews from wpaulino and dunxen via 2888f76August 11, 2023 16:01
@waterson
watersonforce-pushed the create-channel-after-accept branch from 4e4bec7 to 2888f76CompareAugust 11, 2023 16:01
dunxen
dunxen previously approved these changes Aug 11, 2023

@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.

Oops, one issue (we fail to send an error message when failing the channel) and a few nits.

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
peer_state.inbound_v1_channel_by_id.retain(|chan_id, chan| process_unfunded_channel_tick(chan_id, &mut chan.context, &mut chan.unfunded_context));

for (chan_id, req) in peer_state.inbound_channel_request_by_id.iter_mut() {
if { req.ticks_remaining -= 1 ; req.ticks_remaining } <= 0 {

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.

You can do this updating in the retain body.

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.

Ope, hmm... after addressing the issue below I think that it might make more sense to have a separate loop. In particular, the retain lambda gets sad about the use of peer_state.

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.

Ah, you can make it less sad by explicitly taking reference to the inner variables separately as individual variables before the retain, but its not all that critical.

Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs
@waterson
watersonforce-pushed the create-channel-after-accept branch 3 times, most recently from 74e3c4a to d53b2ffCompareAugust 14, 2023 02:33
Create a new table in 'peer_state' to maintain unaccepted inbound
channels; i.e., a channel for which we've received an 'open_channel'
message but that user code has not yet confirmed for acceptance. When
user code accepts the channel (e.g. via 'accept_inbound_channel'),
create the channel object and as before.
Currently, the 'open_channel' message eagerly creates an
InboundV1Channel object before determining if the channel should be
accepted. Because this happens /before/ the channel has been assigned
a user identity (which happens in the handler for OpenChannelRequest),
the channel is assigned a random user identity. As part of the
creation process, the channel's cryptographic material is initialized,
which then uses this randomly generated value for the user's channel
identity e.g. in SignerProvider::generate_channel_keys_id.
By delaying the creation of the InboundV1Channel until /after/ the
channel has been accepted, we ensure that we defer cryptographic
initialization until we have given the user the opportunity to assign
an identity to the channel.

@dunxendunxen 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.

Thanks! Small nit.

events::MessageSendEvent::HandleError {
node_id: counterparty_node_id,
action: msgs::ErrorAction::SendErrorMessage {
msg: msgs::ErrorMessage { channel_id: chan_id.clone(), data: "Channel force-closed".to_owned() }

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.

I think we need a clearer description in the message here. I know we might not know the real reason for not letting the request time out, but maybe we could just say:

"Channel force-closed due to acceptance timeout" or something better. What do you think?

P.S. I've added the missing MessageSendEvent in #2496, which we I will rebase on main when this PR lands.

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.

There's no conflict between the PRs, so landed that one.

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.

Oh, right lol

@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.

LGTM, thanks!

counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
their_features: &InitFeatures, msg: &msgs::OpenChannel, user_id: u128, config: &UserConfig,
current_chain_height: u32, logger: &L, outbound_scid_alias: u64
current_chain_height: u32, logger: &L, outbound_scid_alias: u64, is_0conf: bool,

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.

oubtound_scid_alias is now unused (always zero), so we should drop the argument here.

/// the peer is the counterparty. If the channel is accepted, then the entry in this table is
/// removed, and an InboundV1Channel is created and placed in the `inbound_v1_channel_by_id` table. If
/// the channel is rejected, then the entry is simply removed.
pub(super) inbound_channel_request_by_id: HashMap<[u8; 32], InboundChannelRequest>,

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.

Oops we also need to wipe this on peer disconnection and when handling errors from peers, I'll do that in a quick followup.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@waterson@dunxen@codecov-commenter@TheBlueMatt@wpaulino@alecchendev