Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Order blinded paths by reliability criteria #2912

Merged
merged 2 commits into from
Mar 7, 2024

Conversation

jkczyz
Copy link
Contributor

@jkczyz jkczyz commented Feb 28, 2024

Using a Tor-only node as the introduction node may result in high latency and thus poor reliability when sending onion messages. #2911 preferred selecting nodes that aren't Tor-only. This PR further prefers using a one-hop blinded path over Tor-only nodes if the recipient node is announced. Further, it also prefers more well-connected nodes in terms of number of channels over less-connected nodes.

When forming blinded paths, using a reliable node as the introduction
node is important to ensure onion message reliability. Order blinded
paths by how well-connected the introduction node is as a proxy for
reliability.

For short paths (e.g., when the sender and recipient share an LSP), this
may also result in a scenario where initiating a direct connection isn't
necessary. That is helpful when using RGS since it currently doesn't
include node announcements and thus cannot initiate a direct connection.
If a node is announced, prefer using a one-hop blinded path with it as
the introduction node to using a two-hop blinded path with a Tor-only
introduction node. The one-hop blinded path is more reliable, thus only
use Tor-only nodes if the recipient is unannounced. And then, prefer
non-Tor-only nodes.
Copy link

coderabbitai bot commented Feb 28, 2024

Walkthrough

This update enhances the Lightning Network's efficiency and privacy by refining the logic for path selection in blinded paths and onion messaging. It introduces smarter selection criteria for nodes, prioritizing non-Tor nodes for better connectivity and more connected nodes for robust path construction. Additionally, a new test ensures these preferences are correctly applied, aligning with broader goals to improve privacy and reliability in the network's messaging capabilities.

Changes

Files Change Summary
.../ln/offers_tests.rs - Added logic to handle one-hop blinded paths with Tor-only peers.
- Added a test for preferring more connected nodes in blinded paths.
.../onion_message/messenger.rs - Updated introduction node selection for messaging, including Tor status and connectivity considerations in path selection.

Related issues

Poem

In the digital realm, where the rabbits hop,
A new path they find, where no messages drop.
Tor or not, they cleverly choose,
With privacy in mind, there's less to lose.
🐰💡 Through networks vast, with lightning speed,
They weave and dart, with every deed.
A toast to paths, both clear and blind,
By clever rabbits, intricately designed.

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.

Copy link

@coderabbitai coderabbitai bot left a comment

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: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 7ab438d and e105833.
Files selected for processing (2)
  • lightning/src/ln/offers_tests.rs (2 hunks)
  • lightning/src/onion_message/messenger.rs (1 hunks)
Additional comments: 7
lightning/src/ln/offers_tests.rs (3)
  • 262-262: The assertion within the loop checks that the introduction_node_id is neither bob_id nor charlie_id. This is a good practice to ensure that the selection logic for introduction nodes is working as expected. However, it would be beneficial to add a comment explaining the rationale behind these specific checks for future maintainability.
  • 267-278: The logic here tests the scenario where all of Bob's peers are Tor-only nodes, and it asserts that the introduction_node_id equals bob_id. This is a crucial test for the new functionality introduced in this PR, ensuring that one-hop blinded paths are correctly used when all peers are Tor-only. It's well-implemented and directly addresses the PR objectives.
  • 283-328: This test, prefers_more_connected_nodes_in_blinded_paths, is well-structured and effectively tests the new functionality for preferring more connected nodes in blinded paths. It sets up a network topology, manipulates connections, and checks that the most connected node is selected as the introduction node. This directly aligns with the PR's objectives to improve the reliability of sending onion messages by optimizing the selection process for introduction nodes based on connectivity.
lightning/src/onion_message/messenger.rs (4)
  • 361-363: The logic to check if a recipient is announced is straightforward and correctly uses the network_graph to determine if the NodeId derived from the recipient's PublicKey exists in the graph. This is a critical part of the new selection logic for introduction nodes.
  • 370-372: Filtering peers based on the number of channels they have (ensuring they have at least MIN_PEER_CHANNELS) is a sensible approach to prioritize well-connected nodes. This aligns with the PR's objective to improve message delivery reliability by selecting more reliable nodes.
  • 373-375: Excluding Tor-only nodes when the recipient is announced is a significant change that addresses the issue of high latency and poor reliability with Tor-only nodes. This logic correctly implements part of the PR's strategy to prefer one-hop blinded paths and non-Tor nodes for better connectivity.
  • 376-379: The sorting logic to prefer non-Tor nodes with the most channels as the introduction node is well-implemented. Using sort_unstable_by is appropriate here since we don't require the stability of the sort. This sorting is crucial for optimizing the selection process of introduction nodes based on connectivity.

@@ -250,7 +250,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() {
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);

let tor = SocketAddress::OnionV2([255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]);
announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor);
announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor.clone());
Copy link

@coderabbitai coderabbitai bot Feb 28, 2024

Choose a reason for hiding this comment

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

The use of tor.clone() in announce_node_address is unnecessary since SocketAddress::OnionV2 implements the Copy trait. This means the tor variable can be passed directly without cloning, which would be more efficient.

- announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor.clone());
+ announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor);

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
announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor.clone());
announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you point me to lines of code where it implements the Copy trait?

Copy link

Choose a reason for hiding this comment

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

@jkczyz, the output from the search does not directly show the Copy trait implementation for the SocketAddress enum. The snippet provided includes the definition of SocketAddress but does not include any derive attributes that might indicate the implementation of the Copy trait. It's possible that the relevant part of the code was not included in the output snippet. Without direct evidence from the provided output, I cannot confirm the Copy trait implementation for SocketAddress::OnionV2. My previous statement regarding the unnecessary use of .clone() may have been incorrect without this confirmation.

Analysis chain
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Search for the definition of `SocketAddress` and check if it implements the `Copy` trait.
rg "enum SocketAddress" -A 10

Length of output: 1118

Comment on lines +382 to +390
.map(|(pubkey, _, _)| vec![pubkey, recipient])
.map(|node_pks| BlindedPath::new_for_message(&node_pks, &*self.entropy_source, secp_ctx))
.take(MAX_PATHS)
.collect::<Result<Vec<_>, _>>();

match paths {
Ok(paths) if !paths.is_empty() => Ok(paths),
_ => {
if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) {
if is_recipient_announced {
Copy link

@coderabbitai coderabbitai bot Feb 28, 2024

Choose a reason for hiding this comment

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

Tip

Codebase Verification

The verification process did not find evidence of tests covering the scenario where no paths are found despite the recipient being announced, supporting the suggestion to add targeted tests for the fallback logic to one-hop paths. It's important to ensure comprehensive test coverage for this specific case to maintain robustness in error handling and fallback mechanisms.

Analysis chain

The logic to map peers to BlindedPath and take only up to MAX_PATHS paths is correctly implemented. However, it's important to ensure that the error handling when no paths are found (especially when the recipient is announced) is thoroughly tested to avoid scenarios where a one-hop path could have been used but wasn't due to an oversight.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# It's recommended to add tests specifically covering the scenario where no paths are found
# despite the recipient being announced, ensuring the fallback to a one-hop path works as expected.
echo "Suggest adding targeted tests for the fallback logic to one-hop paths."

Length of output: 150



Script:

#!/bin/bash
# First, find test files related to onion_message or messenger functionality
fd 'test' --type f | grep -E 'onion_message|messenger|BlindedPath'

# If relevant test files are found, search within those files for tests covering the specific scenario
# Note: The actual search within files will be planned based on the output of the first command

Length of output: 114



Script:

#!/bin/bash
# Search within the identified test file for mentions of the scenario of interest
rg -i 'no paths found|recipient announced|one-hop path|MAX_PATHS' lightning/src/onion_message/functional_tests.rs

Length of output: 115

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that scenario covered in creates_and_pays_for_offer_using_one_hop_blinded_path?

Copy link

Choose a reason for hiding this comment

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

Given the information available and the results of the script execution, I couldn't find a test named creates_and_pays_for_offer_using_one_hop_blinded_path within the lightning/src/onion_message/ directory. It's possible that the test might not exist under that exact name, or it could be located in a different part of the codebase. If you have more details about the test's location or its exact name, that could help in locating it.

Analysis chain
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Search for the test `creates_and_pays_for_offer_using_one_hop_blinded_path` within the codebase.
rg 'fn creates_and_pays_for_offer_using_one_hop_blinded_path' lightning/src/onion_message/

Length of output: 92

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is located in file lightning/src/ln/offers_tests.rs.

Copy link

Choose a reason for hiding this comment

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

@jkczyz: The test creates_and_pays_for_offer_using_one_hop_blinded_path in lightning/src/ln/offers_tests.rs indeed covers the scenario of using a one-hop blinded path for offer payment. It verifies that an offer can be paid through such a path and checks the use of ephemeral public keys instead of exposing the node's public key, with the node's public key still being used as the introduction node of the blinded path. This test ensures that the functionality for creating and paying for offers using a one-hop blinded path is working as expected.

Analysis chain
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Extract the content of the test function from the specified file.
rg --context 50 'fn creates_and_pays_for_offer_using_one_hop_blinded_path' lightning/src/ln/offers_tests.rs

Length of output: 4238

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

LGTM, thanks.

Copy link
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -364,13 +364,17 @@ where
network_graph
.node(&NodeId::from_pubkey(pubkey))
.filter(|info| info.channels.len() >= MIN_PEER_CHANNELS)
.map(|info| (*pubkey, info.is_tor_only()))
.map(|info| (*pubkey, info.is_tor_only(), info.channels.len()))
Copy link
Contributor

Choose a reason for hiding this comment

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

I think choosing the right introduction points in order to optimize for a specific metric such as reliability is very related to finding optimal autopilot/attachment strategies. Using the node degree as a proxy metric for reliability seems like a solid first step, especially if we're talking about payment reliability.

A few more thoughts though: Further down the road we could also entertain a few other metrics that could make sense, for example optimizing for betweenness centrality or choosing introduction points according to k-Center optimization. (Some of our simulation results in this paper might be of interest here, see for example Fig. 1). Also, we could account for node uptime (regularity of node announcements?) or latency metrics, that might become available as part of the attributable errors proposal?

Doing anything more than just scoring by node degree might of course require us to pre-calculate and store more per-node metrics, so would probably only make sense if we'd ever come around to introduce a node score, possibly as part of #63?

@tnull tnull merged commit 9bac73b into lightningdevkit:main Mar 7, 2024
13 of 16 checks passed
k0k0ne pushed a commit to bitlightlabs/rust-lightning that referenced this pull request Sep 30, 2024
v0.0.123 - May 08, 2024 - "BOLT12 Dust Sweeping"

API Updates
===========

 * To reduce risk of force-closures and improve HTLC reliability the default
   dust exposure limit has been increased to
   `MaxDustHTLCExposure::FeeRateMultiplier(10_000)`. Users with existing
   channels might want to consider using
   `ChannelManager::update_channel_config` to apply the new default (lightningdevkit#3045).
 * `ChainMonitor::archive_fully_resolved_channel_monitors` is now provided to
   remove from memory `ChannelMonitor`s that have been fully resolved on-chain
   and are now not needed. It uses the new `Persist::archive_persisted_channel`
   to inform the storage layer that such a monitor should be archived (lightningdevkit#2964).
 * An `OutputSweeper` is now provided which will automatically sweep
   `SpendableOutputDescriptor`s, retrying until the sweep confirms (lightningdevkit#2825).
 * After initiating an outbound channel, a peer disconnection no longer results
   in immediate channel closure. Rather, if the peer is reconnected before the
   channel times out LDK will automatically retry opening it (lightningdevkit#2725).
 * `PaymentPurpose` now has separate variants for BOLT12 payments, which
   include fields from the `invoice_request` as well as the `OfferId` (lightningdevkit#2970).
 * `ChannelDetails` now includes a list of in-flight HTLCs (lightningdevkit#2442).
 * `Event::PaymentForwarded` now includes `skimmed_fee_msat` (lightningdevkit#2858).
 * The `hashbrown` dependency has been upgraded and the use of `ahash` as the
   no-std hash table hash function has been removed. As a consequence, LDK's
   `Hash{Map,Set}`s no longer feature several constructors when LDK is built
   with no-std; see the `util::hash_tables` module instead. On platforms that
   `getrandom` supports, setting the `possiblyrandom/getrandom` feature flag
   will ensure hash tables are resistant to HashDoS attacks, though the
   `possiblyrandom` crate should detect most common platforms (lightningdevkit#2810, lightningdevkit#2891).
 * `ChannelMonitor`-originated requests to the `ChannelSigner` can now fail and
   be retried using `ChannelMonitor::signer_unblocked` (lightningdevkit#2816).
 * `SpendableOutputDescriptor::to_psbt_input` now includes the `witness_script`
   where available as well as new proprietary data which can be used to
   re-derive some spending keys from the base key (lightningdevkit#2761, lightningdevkit#3004).
 * `OutPoint::to_channel_id` has been removed in favor of
   `ChannelId::v1_from_funding_outpoint` in preparation for v2 channels with a
   different `ChannelId` derivation scheme (lightningdevkit#2797).
 * `PeerManager::get_peer_node_ids` has been replaced with `list_peers` and
   `peer_by_node_id`, which provide more details (lightningdevkit#2905).
 * `Bolt11Invoice::get_payee_pub_key` is now provided (lightningdevkit#2909).
 * `Default[Message]Router` now take an `entropy_source` argument (lightningdevkit#2847).
 * `ClosureReason::HTLCsTimedOut` has been separated out from
   `ClosureReason::HolderForceClosed` as it is the most common case (lightningdevkit#2887).
 * `ClosureReason::CooperativeClosure` is now split into
   `{Counterparty,Locally}Initiated` variants (lightningdevkit#2863).
 * `Event::ChannelPending::channel_type` is now provided (lightningdevkit#2872).
 * `PaymentForwarded::{prev,next}_user_channel_id` are now provided (lightningdevkit#2924).
 * Channel init messages have been refactored towards V2 channels (lightningdevkit#2871).
 * `BumpTransactionEvent` now contains the channel and counterparty (lightningdevkit#2873).
 * `util::scid_utils` is now public, with some trivial utilities to examine
   short channel ids (lightningdevkit#2694).
 * `DirectedChannelInfo::{source,target}` are now public (lightningdevkit#2870).
 * Bounds in `lightning-background-processor` were simplified by using
   `AChannelManager` (lightningdevkit#2963).
 * The `Persist` impl for `KVStore` no longer requires `Sized`, allowing for
   the use of `dyn KVStore` as `Persist` (lightningdevkit#2883, lightningdevkit#2976).
 * `From<PaymentPreimage>` is now implemented for `PaymentHash` (lightningdevkit#2918).
 * `NodeId::from_slice` is now provided (lightningdevkit#2942).
 * `ChannelManager` deserialization may now fail with `DangerousValue` when
    LDK's persistence API was violated (lightningdevkit#2974).

Bug Fixes
=========

 * Excess fees on counterparty commitment transactions are now included in the
   dust exposure calculation. This lines behavior up with some cases where
   transaction fees can be burnt, making them effectively dust exposure (lightningdevkit#3045).
 * `Future`s used as an `std::...::Future` could grow in size unbounded if it
   was never woken. For those not using async persistence and using the async
   `lightning-background-processor`, this could cause a memory leak in the
   `ChainMonitor` (lightningdevkit#2894).
 * Inbound channel requests that fail in
   `ChannelManager::accept_inbound_channel` would previously have stalled from
   the peer's perspective as no `error` message was sent (lightningdevkit#2953).
 * Blinded path construction has been tuned to select paths more likely to
   succeed, improving BOLT12 payment reliability (lightningdevkit#2911, lightningdevkit#2912).
 * After a reorg, `lightning-transaction-sync` could have failed to follow a
   transaction that LDK needed information about (lightningdevkit#2946).
 * `RecipientOnionFields`' `custom_tlvs` are now propagated to recipients when
   paying with blinded paths (lightningdevkit#2975).
 * `Event::ChannelClosed` is now properly generated and peers are properly
   notified for all channels that as a part of a batch channel open fail to be
   funded (lightningdevkit#3029).
 * In cases where user event processing is substantially delayed such that we
   complete multiple round-trips with our peers before a `PaymentSent` event is
   handled and then restart without persisting the `ChannelManager` after having
   persisted a `ChannelMonitor[Update]`, on startup we may have `Err`d trying to
   deserialize the `ChannelManager` (lightningdevkit#3021).
 * If a peer has relatively high latency, `PeerManager` may have failed to
   establish a connection (lightningdevkit#2993).
 * `ChannelUpdate` messages broadcasted for our own channel closures are now
   slightly more robust (lightningdevkit#2731).
 * Deserializing malformed BOLT11 invoices may have resulted in an integer
   overflow panic in debug builds (lightningdevkit#3032).
 * In exceedingly rare cases (no cases of this are known), LDK may have created
   an invalid serialization for a `ChannelManager` (lightningdevkit#2998).
 * Message processing latency handling BOLT12 payments has been reduced (lightningdevkit#2881).
 * Latency in processing `Event::SpendableOutputs` may be reduced (lightningdevkit#3033).

Node Compatibility
==================

 * LDK's blinded paths were inconsistent with other implementations in several
   ways, which have been addressed (lightningdevkit#2856, lightningdevkit#2936, lightningdevkit#2945).
 * LDK's messaging blinded paths now support the latest features which some
   nodes may begin relying on soon (lightningdevkit#2961).
 * LDK's BOLT12 structs have been updated to support some last-minute changes to
   the spec (lightningdevkit#3017, lightningdevkit#3018).
 * CLN v24.02 requires the `gossip_queries` feature for all peers, however LDK
   by default does not set it for those not using a `P2PGossipSync` (e.g. those
   using RGS). This change was reverted in CLN v24.02.2 however for now LDK
   always sets the `gossip_queries` feature. This change is expected to be
   reverted in a future LDK release (lightningdevkit#2959).

Security
========
0.0.123 fixes a denial-of-service vulnerability which we believe to be reachable
from untrusted input when parsing invalid BOLT11 invoices containing non-ASCII
characters.
 * BOLT11 invoices with non-ASCII characters in the human-readable-part may
   cause an out-of-bounds read attempt leading to a panic (lightningdevkit#3054). Note that all
   BOLT11 invoices containing non-ASCII characters are invalid.

In total, this release features 150 files changed, 19307 insertions, 6306
deletions in 360 commits since 0.0.121 from 17 authors, in alphabetical order:

 * Arik Sosman
 * Duncan Dean
 * Elias Rohrer
 * Evan Feenstra
 * Jeffrey Czyz
 * Keyue Bao
 * Matt Corallo
 * Orbital
 * Sergi Delgado Segura
 * Valentine Wallace
 * Willem Van Lint
 * Wilmer Paulino
 * benthecarman
 * jbesraa
 * olegkubrakov
 * optout
 * shaavan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants