-
Notifications
You must be signed in to change notification settings - Fork 366
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
Optional compact blinded path creation #3080
Optional compact blinded path creation #3080
Conversation
2d2a087
to
3433b70
Compare
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #3080 +/- ##
==========================================
+ Coverage 89.84% 89.86% +0.01%
==========================================
Files 119 119
Lines 97551 97834 +283
Branches 97551 97834 +283
==========================================
+ Hits 87644 87916 +272
- Misses 7332 7350 +18
+ Partials 2575 2568 -7 ☔ View full report in Codecov by Sentry. |
3433b70
to
1d1bcba
Compare
} | ||
}, | ||
} | ||
fn create_compact_blinded_paths< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is a pretty awkward API. IMO whether the intro and forwarding hops are SCID-based should all be one thing (is it a "long-lived" path), but here we have the caller pick whether the middle nodes are compact in the argument and the function call decides if the intro node is compact, splitting the two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't really have the implementation pick without parameterizing it with a ShortChannelIdLookUp
, which we removed in the #3011 (see #3011 (comment)). Also, once we have three-hop blinded paths, the implementation will need to make the decision for the additional hop using a NetworkGraph
, as it does for the introduction node. Do you prefer re-introducing ShortChannelIdLookUp
so that it is all in one place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't really have the implementation pick without parameterizing it with a ShortChannelIdLookUp, which we removed in the #3011 (see #3011 (comment)).
We could go the other way, right? Always create a non-compact path (just do whatever the hops passed say to do) and then have the caller compact the path if they want. That doesn't allow us to communicate to the MessageRouter
that we want a fewer-hop-count path, though.
I guess maybe the variation between create_blinded_paths
taking PublicKey
s and create_compact_blinded_paths
taking ForwardNode
s is maybe enough, it just seems weird that the scids in ForwardNode
s are Option
al in that API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could go the other way, right? Always create a non-compact path (just do whatever the hops passed say to do) and then have the caller compact the path if they want. That doesn't allow us to communicate to the
MessageRouter
that we want a fewer-hop-count path, though.
For the introduction node, the caller can't compact if they don't have a NetworkGraph
to use, which ChannelManager
doesn't directly (only via DefaultRouter
). For intermediate nodes, the caller can't compact after the path is already built since the scid is in the encrypted data. And for three-hop paths, the same NetworkGraph
issues arises.
I guess maybe the variation between
create_blinded_paths
takingPublicKey
s andcreate_compact_blinded_paths
takingForwardNode
s is maybe enough, it just seems weird that the scids inForwardNode
s areOption
al in that API.
Yeah, I think that may be the most straight-forward option. As for the Option
al scid in ForwardNode
, it makes degrading to a partial compact path (i.e., only introduction node compact) simple. See #3011 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, maybe I'm just being grouchy, I guess its fine.
lightning/src/ln/channelmanager.rs
Outdated
@@ -8546,8 +8547,8 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { | |||
/// | |||
/// # Privacy | |||
/// | |||
/// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the offer. | |||
/// However, if one is not found, uses a one-hop [`BlindedPath`] with | |||
/// Uses [`MessageRouter::create_compact_blinded_paths`] to construct a [`BlindedPath`] for the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this should be configurable - I'd like to be able to communicate to LDK whether I want a "long-lived" offer or a "short-lived" one, and that should feed into the number of hops and whether we use compact paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How we do that is the open question that I posed in #3011 (comment).
Regarding number of hops, should we prefer more hops for short-lived offers? Should we communicate this to MessageRouter
in some way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How we do that is the open question that I posed in #3011 (comment).
I don't have a super strong opinion on how, the options you list there all seem fine.
Regarding number of hops, should we prefer more hops for short-lived offers? Should we communicate this to MessageRouter in some way?
IMO yes and yes. Presumably when we do three-hop blinded paths it should only be for short-lived offers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went with the approach of passing the absolute expiry to create_offer_builder
.
1d1bcba
to
5c28c67
Compare
Can be rebased now that #3011 landed, also CI needs a fix. |
d8f306f
to
102ffe4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically LGTM. CI needs another fix.
/// Creates [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed to be | ||
/// direct peers with the `recipient`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These docs are identical to create_blinded_paths
above, maybe could use some more information about what makes this different/when this should be used instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching that. I meant to update them before moving out of draft, but it seems I forgot.
102ffe4
to
e9b2cf4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically LGTM
lightning/src/ln/channelmanager.rs
Outdated
/// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the offer. However, if one is not | ||
/// found, uses a one-hop [`BlindedPath`] with [`ChannelManager::get_our_node_id`] as the | ||
/// introduction node instead. In the latter case, the node must be announced, otherwise, there | ||
/// is no way to find a path to the introduction in order to send the [`InvoiceRequest`]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably include some text about how offers with an expiry less than $PUBLIC_CONSTANT may have somewhat better privacy and will be more compact whereas long-lived offers will use additional data to improve longevity of the offer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth making a UserConfig
parameter for this instead of using the hardcoded constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, if we're gonna do that we should just expose a bool to select if the offer is compact directly. I'm not sure sure if it's worth bothering, though, people really shouldn't have a compact offer for an offer that doesn't expire and I'm not really sure how much anyone wants an offer that expires in a month (vs forever or in an hour), it seems like there's going to be a very strong bimodal distribution (if there's even a top vs just being no-expiry).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. Leaving as is except using a public constant. Updated docs accordingly.
lightning/src/ln/channelmanager.rs
Outdated
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. When parameterized by | ||
/// [`DefaultRouter`] (and thus using [`DefaultMessageRouter`), however, if a path is not found, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"When parameterized by... (and thus using ..), however, if a path is not found, ..." sounds pretty awkward to me, is there a way to rephrase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-phrased this quite a bit now. Let me know if it is less awkward.
51036ec
to
96ad768
Compare
lightning/src/ln/channelmanager.rs
Outdated
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for | ||
/// privacy implications. | ||
/// | ||
/// The [`Router`] used to parameterized [`ChannelManager`] may also affect privacy since it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're gonna describe the specific behavior of DefaultMessageRouter
here we should leave a comment in DefaultMessageRouter
reminding us to update the docs here if we change the implementation (but it might just be better to link to DefaultMessageRouter
and discuss its behavior there).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. Re-arranged the docs accordingly.
lightning/src/ln/channelmanager.rs
Outdated
/// - [`MessageRouter::create_blinded_paths`] when long-lived. | ||
/// | ||
/// Using compact [`BlindedPath`]s may provide better privacy as more hops can be used with the same | ||
/// amount of bytes. However, since they use short channel ids instead of pubkeys, they are more |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure its because of the byte count (I guess it is, in part), but more that the router could/should be selecting a longer path if its compact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-worded
96ad768
to
ffbe363
Compare
lightning/src/ln/channelmanager.rs
Outdated
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`]. | ||
/// | ||
/// Errors if the `MessageRouter` errors or returns an empty `Vec`. | ||
fn create_blinded_path(&self) -> Result<BlindedPath, ()> { | ||
let recipient = self.get_our_node_id(); | ||
let secp_ctx = &self.secp_ctx; | ||
|
||
let peers = self.per_peer_state.read().unwrap() | ||
.iter() | ||
.filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_onion_messages()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a change in this PR, but is there a reason we don't filter by connected peers here and below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, looks like a mistake. I've added a fix.
let now = Duration::from_secs( | ||
self.highest_seen_timestamp.load(Ordering::Acquire) as u64 | ||
); | ||
#[cfg(feature = "std")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Until we upgrade to rust-bitcoin 0.32, we should avoid assuming we can access time even with std :(.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... we are already doing so in timer_tick_occurred
and OffersMessageHandler
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I'd missed that, we need to fix that (or mutiny is gonna be mad...).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anything blocking us from upgrading now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just someone doing the work, I think. @tnull should chime in though, it may be that BDK is on 0.31 and we want to ship an 0.31 release first so that we can sync with the existing BDK code before jumping to 0.32.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I discussed that with the BDK team in the meeting last week. BDK is close to finishing the upgrade and it will land ~next release, at the very least before the feature that keeps LDK Node from upgrading (data model backwards compat). So we're free to (and in fact should ASAP) upgrade to 0.32. I can see to prioritize it by the end of the week. Would this be sufficient to have it land it first, so that we don't have to deal with the things mentioned above here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, preferably so. I'm not sure what our alternative is, though I don't think we're in any big rush to land this. Presumably we'll want it for the next release but waiting on 0.32 shouldn't hold up the review at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, now tracking here: #3100
Will see to pick it up soon if nobody is already working on it.
ffbe363
to
d2d1694
Compare
Needs rebase, and feel free to squash. |
@TheBlueMatt Currently we don't use the compact representation for reply paths. In #2793, we'll soon only create three-hop paths for the compact representation. Are we ok with using only two hops for reply paths? |
An upcoming change to the MessageRouter trait will require reusing DefaultMessageRouter::create_blinded_paths. Move the code to a utility function so facilitate this.
d2d1694
to
ae6e5ff
Compare
Using compact blinded paths isn't always necessary or desirable. For instance, reply paths are communicated via onion messages where space isn't a premium unlike in QR codes. Additionally, long-lived paths could become invalid if the channel associated with the SCID is closed. Refactor MessageRouter::create_blinded_paths into two methods: one for compact blinded paths and one for normal blinded paths.
There's no need to save space when creating reply paths since they are part of onion messages rather than in QR codes. Use normal blinded paths for these instead as they are less likely to become invalid in case of channel closure.
When an offer is short-lived, the likelihood of a channel used in a compact blinded path going away is low. Require passing the absolute expiry of an offer to ChannelManager::create_offer_builder so that it can be used to determine whether or not compact blinded path should be used. Use the same criteria for creating blinded paths for refunds as well.
When reconnecting nodes, make sure to notify OnionMessenger that the nodes are now connected.
When calling MessageRouter::create_blinded_path, ChannelManager was including disconnected peers. Filter peers such that only connected ones are included. Otherwise, the resulting BlindedPath may not work.
The docs assumed ChannelManager is parameterized by DefaultRouter, which may not be the case. Clarify the behavior is specific to using DefaultRouter.
ae6e5ff
to
c17a026
Compare
Ah, good point. Yea, we might need a more holistic way to think about how much we're revealing when we expose a different blinded path for payments than we do for messaging. Really we use the same path for both to avoid revealing info that can be used to triangulate, but that's a somewhat larger change so I think we can let it slide for now and come back to it. |
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`], | ||
/// will included a [`BlindedPath`] created using: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`], | |
/// will included a [`BlindedPath`] created using: | |
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`] | |
/// will include a [`BlindedPath`] created using: |
Follow-up to #3011, which expands the
MessageRouter
trait with a separatecreate_compact_blinded_path
method. This allows callers to decided whether or not to use compact blinded paths depending on the context. UpdatesChannelManager
to only use compact blinded paths forOffer::paths
andRefund::paths
. Reply paths use non-compact blinded paths instead.Based on #3011.