Skip to content

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@TheBlueMatt@arik-so
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Log cases where an onion failure cannot be attributed or interpreted by joostjager · Pull Request #3629 · lightningdevkit/rust-lightning · GitHub
Skip to content

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@TheBlueMatt@arik-so
, '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" + ' Log cases where an onion failure cannot be attributed or interpreted by joostjager · Pull Request #3629 · lightningdevkit/rust-lightning · GitHub
Skip to content

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@TheBlueMatt@arik-so
, '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('^' + ".*" + ' Log cases where an onion failure cannot be attributed or interpreted by joostjager · Pull Request #3629 · lightningdevkit/rust-lightning · GitHub
Skip to content

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@TheBlueMatt@arik-so
, '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); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Log cases where an onion failure cannot be attributed or interpreted by joostjager · Pull Request #3629 · lightningdevkit/rust-lightning · GitHub
Skip to content

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

Log cases where an onion failure cannot be attributed or interpreted - #3629

Merged
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures
Mar 4, 2025
Merged

Log cases where an onion failure cannot be attributed or interpreted#3629
arik-so merged 4 commits into
lightningdevkit:mainfrom
joostjager:log-attribution-failures

Conversation

@joostjager

@joostjagerjoostjager commented Feb 28, 2025

Copy link
Copy Markdown
Contributor

Create more visibility into these edge cases. The non-attributable failure in particular can be used to disrupt sender operation and it is therefore good to at least log these cases clearly.

Additionally a bug is fixed where an unreadable failure with valid hmac wasn't properly attributed to a node.

Comment threadlightning/src/ln/onion_utils.rs Outdated
Ok(p) => p,
Err(_) => return,
};
let decrypt_result = decrypt_onion_error_packet(&mut encrypted_packet, shared_secret);

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.

Check hmac first to distinguish between unreadable failures and hmac mismatches.

@codecov

codecovBot commented Feb 28, 2025

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 89.17%. Comparing base (eaeed77) to head (1d40811).

Additional details and impacted files
@@ Coverage Diff @@## main #3629 +/- ##
========================================
Coverage 89.16% 89.17% ========================================
Files 152 152 Lines 118791 118947 +156 Branches 118791 118947 +156 ========================================
+ Hits 105921 106068 +147 - Misses 10312 10316 +4 - Partials 2558 2563 +5 

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

@joostjager

joostjager commented Feb 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Coverage reports suggests more test coverage needed...

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 5 times, most recently from 56b0aa7 to 70c8e56CompareFebruary 28, 2025 13:16
Comment threadlightning/src/ln/onion_utils.rs Outdated
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
res = Some(FailureLearnings {

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is a bug fix. Previously unreadable failures weren't attributable even though the hmac checked out.

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 70c8e56 to 47caa1eCompareFebruary 28, 2025 13:24
fn build_test_path() -> Path {
Path {
hops: vec![
RouteHop {

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.

rustfmt wanted this

.unwrap(),
channel_features: ChannelFeatures::empty(),
node_features: NodeFeatures::empty(),
short_channel_id: 1,

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

it is a move, but just these short_channel_id's made unique to make it easier to test things for attr errors

@joostjager

Copy link
Copy Markdown
ContributorAuthor

Tests added

@joostjager
joostjagerforce-pushed the log-attribution-failures branch 3 times, most recently from cdda315 to fc11fe4CompareFebruary 28, 2025 13:49
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated
Comment threadlightning/src/ln/onion_utils.rs Outdated

let network_update = Some(NetworkUpdate::NodeFailure {
node_id: route_hop.pubkey,
is_permanent: true,

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.

IIRC is_permanentNodeFailures result in removing the node from the graph entirely, which seems a bit harsh, I think?

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.

The same was already done for a missing failure code, so it seemed reasonable to apply the same penalty for the more severe case where the message cannot even be decoded?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think the node is removed for a week? That seems fine to me because in this case there must be a bug in the remote node software.

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.

Hmmmmmmmm, I guess okay if only because we don't have a way to punish all of a node's channels. It does seem like we should find a way to do that, though, without outright graph removal. I know some other stuff does that, but I'd call that legacy needs-updating too :)

Indeed, after a while we'd accept fresh announcements of that node's channels, but generally we don't resync so we'd most likely only get them on restart (or when the node opens new channels).

@joostjager
joostjagerforce-pushed the log-attribution-failures branch from fc11fe4 to 9f16e69CompareMarch 3, 2025 09:33
This function still decrypted the message in-place even when it returned
an error. This is confusing for the caller.
Create more visibility into these edge cases. The non-attributable
failure in particular can be used to disrupt sender operation and it is
therefore good to at least log these cases clearly.
This commit fixes a bug where a node penalty was not applied where it
should.
@joostjager
joostjagerforce-pushed the log-attribution-failures branch from 9f16e69 to f38244cCompareMarch 3, 2025 09:47
@joostjagerjoostjager added the weekly goal Someone wants to land this this week label Mar 3, 2025
packet: &mut Vec<u8>, shared_secret: SharedSecret,
) -> Result<msgs::DecodedOnionErrorPacket, msgs::DecodeError> {
/// Decrypt the error packet in-place.
fn decrypt_onion_error_packet(packet: &mut Vec<u8>, shared_secret: SharedSecret) {

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 almost wonder whether it's one of those instances where in-place processing is what largely contributes to confusion. Getting a result back with the decrypted packet or with the decryption error, without worrying about the input argument getting changed, seems preferable.

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.

The confusion was mainly that this used to be a function that returned a value and still had a side effect too. A side effect that was also needed, because the decrypted packet needs to be processed for the next hop.

Could have returned a decrypted copy in addition to the decoded failure to make it a pure function, probably with some performance implications. But I think now that this function has no return value anymore and only decrypts in-place, it's already a lot better.

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

Labels

weekly goalSomeone wants to land this this week

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@joostjager@TheBlueMatt@arik-so