Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n 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;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

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

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

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

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Disconnect peers on timer ticks to unblock channel state machine - #2293

Merged
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick
May 30, 2023
Merged

Disconnect peers on timer ticks to unblock channel state machine#2293
TheBlueMatt merged 4 commits into
lightningdevkit:mainfrom
wpaulino:disconnect-peers-timer-tick

Conversation

@wpaulino

Copy link
Copy Markdown
Contributor

At times, we've noticed that channels with lnd counterparties do not receive messages we expect to in a timely manner (or at all) after sending them a ChannelReestablish upon reconnection, or a CommitmentSigned message. This can block the channel state machine from making progress, eventually leading to force closes, if any pending HTLCs are committed and their expiration is met.

It seems common wisdom for lnd node operators to periodically restart their node/reconnect to their peers, allowing them to start from a fresh state such that the message we expect to receive hopefully gets sent. We can achieve the same end result by disconnecting peers ourselves (regardless of whether they're a lnd node), which we opt to implement here by awaiting their response within two timer ticks.

Fixes#2282.

@wpaulinowpaulino added this to the 0.0.116 milestone May 13, 2023
@codecov-commenter

codecov-commenter commented May 13, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 57.66% and project coverage change: -0.09⚠️

Comparison is base (4dce209) 90.79% compared to head (09c051f) 90.70%.

❗ Current head 09c051f differs from pull request most recent head 5bf7fac. Consider uploading reports for the commit 5bf7fac 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 #2293 +/- ##
==========================================
- Coverage 90.79% 90.70% -0.09% 
==========================================
Files 104 104 Lines 53033 53162 +129 Branches 53033 53162 +129 ==========================================
+ Hits 48153 48223 +70 - Misses 4880 4939 +59 
Impacted FilesCoverage Δ
lightning/src/ln/msgs.rs85.07% <0.00%> (-0.06%)⬇️
lightning/src/ln/wire.rs49.09% <2.17%> (-7.76%)⬇️
lightning/src/ln/peer_handler.rs58.85% <23.07%> (-0.52%)⬇️
lightning/src/ln/channel.rs89.78% <86.66%> (-0.02%)⬇️
lightning/src/ln/functional_tests.rs98.25% <98.48%> (+<0.01%)⬆️
lightning/src/ln/channelmanager.rs87.13% <100.00%> (+0.02%)⬆️

... and 6 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 15c311e to 6353683CompareMay 13, 2023 21:59
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Grr, sorry for the delay in responding here. So I'm not sure what to do about expected-CS.

If we have an inbound HTLC that we remove, send a CS, receive an RAA and then don't receive the expected CS so we can RAA we'll (a) no longer have any state about this HTLC in the channel - its been removed from our state as we never need to care about it in the off-chain state side of things and (b) still force-close the channel if the HTLC times out, as the ChannelMonitor sees that if we broadcast we'll still have the HTLC which we need to time-out.

At least the two state-machine-deadlocks I saw with lnd peers we were waiting on an RAA, and because we're not blocked on an RAA we can make progress (in the form of sending our own CS and then presumably if they're still hung we'll decide to d/c because we're awaiting-RAA), but its kinda awkward there's still a case there where we should d/c but won't.

For now its probably fine, and its better that we do d/c if we have to than nothing, at least because actually fixing this would require state machine tweaks that I don't really want to have to think hard about.

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

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/functional_tests.rs
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 105e9ac to fe3a962CompareMay 18, 2023 19:15
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

MSRV build is sad.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from fe3a962 to 793c2cfCompareMay 21, 2023 00:28

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

Code looks good I think, mostly nits.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/peer_handler.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
let alice_init = msgs::Init { features: nodes[0].node.init_features(), remote_network_address: None };
nodes[1].node.peer_connected(&nodes[0].node.get_our_node_id(), &alice_init, true).unwrap();

// Upon reconnection, Alice sends her `ChannelReestablish` to Bob. Alice, however, hasn't

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.

Can you add another (or just extend the test) to include a channel_ready message? That should emulate the exact behavior we've seen out of lnd.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

It doesn't really matter? They can send channel_ready if they wish, the issue is not receiving channel_reestablish.

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.

Fair, it doesn't matter much I just wanted to match exactly what we've seen in the wild cause I can't readily repro with any peers so its nice to get an exact test to make sure we're good.

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

Code looks good I think, mostly nits.

@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch 2 times, most recently from d767d1d to 09c051fCompareMay 24, 2023 17:33
@TheBlueMatt

Copy link
Copy Markdown
Collaborator

Ugh needs rebase, LGTM, though.

The inner structs of each enum variant already implemented them and we
plan to pass in `Message`s to `enqueue_message` in a future commit.
`enqueue_message` simply adds the message to the outbound queue, it
still needs to be written to the socket with `do_attempt_write_data`.
However, since we immediately return an error causing the socket to be
closed, the message never actually gets sent.
At times, we've noticed that channels with `lnd` counterparties do not
receive messages we expect to in a timely manner (or at all) after
sending them a `ChannelReestablish` upon reconnection, or a
`CommitmentSigned` message. This can block the channel state machine
from making progress, eventually leading to force closes, if any pending
HTLCs are committed and their expiration is met.
It seems common wisdom for `lnd` node operators to periodically restart
their node/reconnect to their peers, allowing them to start from a fresh
state such that the message we expect to receive hopefully gets sent. We
can achieve the same end result by disconnecting peers ourselves
(regardless of whether they're a `lnd` node), which we opt to implement
here by awaiting their response within two timer ticks.
@wpaulino
wpaulinoforce-pushed the disconnect-peers-timer-tick branch from 09c051f to 5bf7facCompareMay 26, 2023 21:41
@wpaulino
wpaulino requested a review from dunxenMay 30, 2023 17:55

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

Looks good. Nothing else from my side.

@TheBlueMatt
TheBlueMatt merged commit eec5ec6 into lightningdevkit:mainMay 30, 2023
@wpaulino
wpaulino deleted the disconnect-peers-timer-tick branch May 30, 2023 19:58
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.

Disconnect peers which don't respond to commitment signed after a while

4 participants

@wpaulino@codecov-commenter@TheBlueMatt@dunxen