Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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" + '
Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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('^' + ".*" + ' Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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('^' + ".*" + ' Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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" + ' Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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('^' + ".*" + ' Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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('^' + ".*" + ' Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz
, '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); } })(); })(); Complete route blinding support by valentinewallace · Pull Request #2812 · lightningdevkit/rust-lightning · GitHub
Skip to content

Complete route blinding support - #2812

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding
Jan 17, 2024
Merged

Complete route blinding support#2812
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
valentinewallace:2023-12-blinded-forwarding

Conversation

@valentinewallace

@valentinewallacevalentinewallace commented Jan 2, 2024

Copy link
Copy Markdown
Contributor

We'll now support forwarding blinded payments as not-the-intro-node. Unblocks advertising the feature bit, though we don't advertise it yet in this PR. Since this completes blinded forwarding support, we also start advertising the feature bit.

Helps address #1970. There are still a few small follow-ups planned after this one.

@codecov-commenter

codecov-commenter commented Jan 2, 2024

Copy link
Copy Markdown

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (62d52c6) 88.50% compared to head (aae39b4) 88.91%.
Report is 10 commits behind head on main.

FilesPatch %Lines
lightning/src/ln/channelmanager.rs75.00%1 Missing ⚠️
lightning/src/ln/peer_handler.rs0.00%1 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@ Coverage Diff @@## main #2812 +/- ##
==========================================
+ Coverage 88.50% 88.91% +0.41% 
==========================================
Files 114 114 Lines 92055 94794 +2739 Branches 92055 94794 +2739 ==========================================
+ Hits 81471 84290 +2819 + Misses 8079 8058 -21 + Partials 2505 2446 -59 

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

@jkczyz
jkczyz self-requested a review January 2, 2024 15:38
@valentinewallacevalentinewallace added this to the 0.0.120 milestone Jan 5, 2024

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

Basically LGTM, I think, though I need to dig in more deeply.

Comment threadlightning/src/ln/channelmanager.rs Outdated
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch 2 times, most recently from bd28d01 to eac0f70CompareJanuary 9, 2024 20:49
@jkczyzjkczyz mentioned this pull request Jan 10, 2024
// Another field will be added here when we support forwarding as a non-intro node.
/// If needed, this determines how this HTLC should be failed backwards, based on whether we are
/// the introduction node.
pub failure: BlindedFailure,

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.

Hmm... maybe this should be named BlindedSource now that it is no longer just use in a failure context?

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.

Hm, it should only be used in a failure context. Could you point me to where you're seeing that?

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.

By "used" I meant more that it is used in this struct even though described "if needed". I suppose the struct name is fine given how it is actually used, but the variable name failure makes it seem like something has already failed when in fact in this context it might not ever. I'm fine if there's not a better name.

Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment on lines +2391 to +2402
pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> {
pub origin_node: &'a Node<'b, 'c, 'd>,
pub expected_path: &'a [&'a Node<'b, 'c, 'd>],
pub recv_value: u64,
pub payment_hash: PaymentHash,
pub payment_secret: Option<PaymentSecret>,
pub event: MessageSendEvent,
pub payment_claimable_expected: bool,
pub clear_recipient_events: bool,
pub expected_preimage: Option<PaymentPreimage>,
pub is_probe: bool,
}

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.

Nice! 😎

Comment on lines +1056 to +1062
fn prop_fees_rng() {
do_prop_fees_rng(true);
do_prop_fees_rng(false);
}

#[cfg(feature = "std")]
fn do_prop_fees_rng(send_min: bool) {

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.

What's the reason for using random values?

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 was written a long time ago to have actual testing for #2514. The random values helped catch some edge cases we weren't handling.

@valentinewallacevalentinewallace mentioned this pull request Jan 10, 2024
60 tasks
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from eac0f70 to 5663ebfCompareJanuary 10, 2024 22:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Because we may have a shorter than usual release cycle for 0.0.120, I moved the tests and the related test util refactors into #2823 in case it gives us a better chance of landing this in time.

Error handling will be completed in upcoming commit(s).
Previously, we were setting the final blinded hop's CLTV expiry height to
best_block_height + total_blinded_path_cltv_delta + shadow_cltv_offset. This is
incorrect, it should instead be set to best_block_height + shadow_cltv_offset
only -- it doesn't make sense to include the delta for the other blinded hops
in the final hop's expiry.
The reason this too-high final cltv value didn't cause test failures previously
is because of a 2nd bug that is fixed in an upcoming commit where the sender
adds the shadow offset twice to the total path CLTV expiry. This 2nd offset
meant that intermediate nodes had some buffer CLTV to subtract their delta from
while still (usually) have enough leftover to meet the expiry in the final hop's
onion.
Necessary to include it in the public PendingHTLCInfo struct in the next commit.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from 5663ebf to ae22997CompareJanuary 11, 2024 16:39
@valentinewallace

Copy link
Copy Markdown
ContributorAuthor

Rebased due to conflicts.

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

Two questions, otherwise LGTM


impl_writeable_tlv_based!(BlindedForward, {
(0, inbound_blinding_point, required),
(1, failure, (default_value, BlindedFailure::FromIntroductionNode)),

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.

Didn't we previously only support forwarding as an intermediate node, so shouldn't the default here be FromBlindedNode?

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.

Ah, no we previously only supported intro node forwarding.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

I'm confused, I read the code here as "if intro_node_blinding_point is set (ie we're the introduction node), set the failure mode to FromBlindedNode, otherwise FromIntroductionNode). Isn't that the wrong way around.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Unrelatedly, FromIntroductionNode should probably read WereIntroductionNode, right?

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Hmm... that reads to me as "were introduction node." Do you think the current name is unclear?

Heh, fair, I read it as "this came from the introduction node" rather than "we're the introduction node"? I guess its a failure so it can be implied that we're the one failing? It doesnt matter too much, though, really.

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

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.

Had to use unwrap_or but did this.

@jkczyzjkczyz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Feel free to squash.

Comment threadlightning/src/ln/onion_payment.rs Outdated
.map(|bp| BlindedForward {
inbound_blinding_point: bp,
failure: intro_node_blinding_point
.map_or(BlindedFailure::FromBlindedNode, |_| BlindedFailure::FromIntroductionNode),

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.

map_or syntax is a bit weird but BlindedFailure::FromBlindedNode is the default value that gets returned if intro_node_blinding_point is None.

Ugh.

Agreed regarding map_or parameters. Might be clearer as:

intro_node_blinding_point.map(|_| BlindedFailure::FromIntroductionNode).or(BlindedFailure::FromBlindedNode)

The excess delta is included in the final RouteHop::cltv_expiry_delta, so by
adding it explicitly to cur_cltv we were erroneously including it twice in the
total cltv expiry.
This could've add up to an extra MAX_SHADOW_CLTV_DELTA_OFFSET (432) blocks to
the total cltv expiry.
Now that we fully support forwarding blinded payments, we should advertise
support so nodes on the network can include us in their blinded paths.
@valentinewallace
valentinewallaceforce-pushed the 2023-12-blinded-forwarding branch from b9531da to aae39b4CompareJanuary 16, 2024 22:47
@coderabbitai

coderabbitaiBot commented Jan 16, 2024

Copy link
Copy Markdown

Walkthrough

The changes reflect enhancements to the blinded payment process within a Lightning Network implementation. A new test ensures three-hop blinded paths work correctly, while handling of failures in multi-hop scenarios has been improved. The BlindedForward structure, PendingHTLCRouting enum, and related functions now accommodate blinded failures. An optionality has been introduced to node blinding points, and the calculation of cltv_expiry_height has been adjusted. Additionally, route blinding can now be set as optional through a new method.

Changes

FilesChange Summary
.../blinded_payment_tests.rsAdded three_hop_blinded_path_success test; updated do_multi_hop_receiver_fail for various failure scenarios.
.../channelmanager.rs, .../onion_payment.rsEnhanced structures and enums (BlindedForward, PendingHTLCRouting, BlindedFailure) to handle blinded failures; updated related functions.
.../msgs.rs, .../onion_utils.rsMade intro_node_blinding_point optional; adjusted cltv_expiry_height in build_onion_payloads.
.../peer_handler.rsIntroduced set_route_blinding_optional method.

Poem

In the code where payments flash,
A rabbit hopped, made a dash,
Through blinded paths, it twirled with glee,
"Hop success!" it cheered, "Privacy spree!" 🐰⚡️🎉

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between ea5de93 and aae39b4.
Files selected for processing (6)
  • lightning/src/ln/blinded_payment_tests.rs (3 hunks)
  • lightning/src/ln/channelmanager.rs (6 hunks)
  • lightning/src/ln/msgs.rs (2 hunks)
  • lightning/src/ln/onion_payment.rs (4 hunks)
  • lightning/src/ln/onion_utils.rs (1 hunks)
  • lightning/src/ln/peer_handler.rs (1 hunks)
Additional comments: 14
lightning/src/ln/onion_payment.rs (3)
  • 15-15: The import of BlindedFailure and BlindedForward types, as well as other related items, is necessary for the new functionality related to route blinding.
  • 73-79: > Note: This review was outside the patches, so it was mapped to the patch with the greatest overlap. Original lines [76-94]

The match arm for msgs::InboundOnionPayload::BlindedForward has been correctly updated to handle the new blinded payment logic, including the introduction of intro_node_blinding_point and the use of check_blinded_forward to validate the payment relay and constraints.

  • 108-114: The logic for creating a PendingHTLCInfo struct has been updated to include the new BlindedForward struct with the inbound_blinding_point and failure fields. This is consistent with the PR's objective to support route blinding.
lightning/src/ln/blinded_payment_tests.rs (1)
  • 493-514: The addition of the three_hop_blinded_path_success test function is consistent with the PR's objective to enhance route blinding capabilities. The test setup and assertions appear to be correct and follow the pattern of existing tests.
lightning/src/ln/peer_handler.rs (1)
  • 308-308: The addition of set_route_blinding_optional to the features struct aligns with the existing pattern of feature flag setters.
lightning/src/ln/msgs.rs (2)
  • 1717-1717: The change to make intro_node_blinding_point an Option<PublicKey> is consistent with the PR objectives and AI-generated summary, which indicates that the intro_node_blinding_point field should reflect the optional nature of this information in the context of route blinding.
  • 2397-2397: The use of intro_node_blinding_point within the BlindedForward variant is consistent with the change to its type. This ensures that the optional nature of the blinding point is correctly handled in the logic related to payment relay and constraints.
lightning/src/ln/channelmanager.rs (7)
  • 205-207: The addition of the failure field to the BlindedForward struct is consistent with the PR's objective to handle blinded failures.
  • 214-214: The blinded_failure method correctly matches against the BlindedForward struct to extract the failure field when present.
  • 310-317: The BlindedFailure enum is well-defined and appropriately differentiates between introduction node and blinded node failures.
  • 3033-3035: The logic to determine if the forwarding is from an introduction node using the presence of intro_node_blinding_point is sound.
  • 4380-4380: The assignment of blinded_failure when creating a PendingHTLCRouting instance is correctly implemented.
  • 9360-9360: The route blinding feature bit is correctly set as optional, aligning with the PR's note that the feature bit is not yet advertised.
  • 9506-9506: The serialization of the BlindedForward struct with the failure field using a TLV-based approach is correctly implemented.

sender_intended_htlc_amt_msat: *final_value_msat,
total_msat,
cltv_expiry_height: cltv,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The cltv_expiry_height calculation has been modified to include excess_final_cltv_expiry_delta. This change could potentially introduce an off-by-one error if cur_cltv is not already inclusive of the current block height. It's important to ensure that cur_cltv represents the correct starting point before the addition of excess_final_cltv_expiry_delta.

To address this, verify that cur_cltv is calculated correctly elsewhere in the codebase, taking into account the current block height. If cur_cltv is already inclusive of the current block height, then this change is correct. Otherwise, adjust the calculation to ensure the correct cltv_expiry_height is set.

- cltv_expiry_height: cur_cltv,+ cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,
cltv_expiry_height: cur_cltv + excess_final_cltv_expiry_delta,

Comment on lines +563 to +567
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTV as u16 - 2)
} else { None };
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), final_cltv_delta);
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), excess_final_cltv_delta_opt);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The variable excess_final_cltv_delta_opt is used to set a CLTV delta that is too low, but the name does not clearly reflect its purpose. Consider renaming it to more accurately describe its function, such as insufficient_final_cltv_delta_opt.

- let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {+ let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck {

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
let excess_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), final_cltv_delta);
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), excess_final_cltv_delta_opt);
let insufficient_final_cltv_delta_opt = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck{
// Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards.
Some(TEST_FINAL_CLTVasu16 - 2)
}else{None};
let(_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2],Some(amt_msat), insufficient_final_cltv_delta_opt);

commitment_signed_dance!(nodes[2], nodes[1], (), false, true, false, false);
},
ReceiveCheckFail::ProcessPendingHTLCsCheck => {
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The assertion on line 684 checks the cltv_expiry against a value derived from the block height and an excess_final_cltv_delta_opt. However, the name excess_final_cltv_delta_opt suggests an excess value, while the context implies it is insufficient. This could lead to confusion. The variable should be renamed to reflect its purpose more clearly, as suggested in the previous comment.

- assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap() as u32);+ assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap() as u32);

Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + excess_final_cltv_delta_opt.unwrap()asu32);
assert_eq!(payment_event_1_2.msgs[0].cltv_expiry, nodes[0].best_block_info().1 + 1 + insufficient_final_cltv_delta_opt.unwrap()asu32);

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@valentinewallace@codecov-commenter@TheBlueMatt@jkczyz