-
Notifications
You must be signed in to change notification settings - Fork 377
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
Compact blinded path creation #3011
Compact blinded path creation #3011
Conversation
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 #3011 +/- ##
==========================================
+ Coverage 89.87% 90.29% +0.42%
==========================================
Files 117 117
Lines 96952 100069 +3117
Branches 96952 100069 +3117
==========================================
+ Hits 87134 90357 +3223
+ Misses 7273 7130 -143
- Partials 2545 2582 +37 ☔ View full report in Codecov by Sentry. |
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/blinded_path/mod.rs
Outdated
|
||
/// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed | ||
/// short channel id from a channel in `network_graph` leading to the introduction node. | ||
pub fn compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) { |
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.
Pedantic but the convention is for setters to use the set_
prefix: https://github.com/rust-lang/rfcs/blob/master/text/0344-conventions-galore.md#gettersetter-apis and I think it would read a bit cleaner in this case.
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... this is not a setter in the normal sense, though, as we don't pass a value to set a field with. Nor is the field private, which would necessitate a setter. It also may not update the field if a value cannot be found in the network graph. Happy to go with a better name. Just not sure if a set_
prefix is appropriate 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.
Still, it does seem a bit strange that we're mutating the blinded path with a fn name that sounds like it could just as well be a straight getter.
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.
Ok, added a use_
prefix. I can see how the docs make it less clear that compact
was a verb in the name.
T: secp256k1::Signing + secp256k1::Verification | ||
>( | ||
&self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>, | ||
&self, recipient: PublicKey, peers: Vec<PublicKey>, scid_lookup: &SL, |
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.
Rather than passing a list of our peers and a trait so that create_blinded_paths
can make a callback to the caller to ask for an SCID for a given peer, shouldn't we just pass in the peers as a ForwardNode
or (PublicKey, u64)
?
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, come to think of it that is probably cleaner. That would also allow the caller to use the compact hop representation only when desired. (e.g., in offer/refund but not in reply paths).
084d070
to
a74e84f
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.
Looks like this needs a rebase.
lightning/src/ln/channelmanager.rs
Outdated
node_id: *node_id, | ||
short_channel_id: peer.channel_by_id | ||
.iter() | ||
.find(|(_, channel)| channel.context().is_usable()) |
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.
Do we want to sort by oldest or biggest or something?
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.
Good idea! Oldest is probably best as this is only for onion messages, so we just want to make sure the channel announcement has been propagated in the gossip.
5d08b1f
to
f3726a7
Compare
Rebased |
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, but IMO we really should make this optional somehow. It could happen in a followup if we want, cause we should also change how many hops we include based on if an offfer is long-lived.
lightning/src/blinded_path/mod.rs
Outdated
|
||
/// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed | ||
/// short channel id from a channel in `network_graph` leading to the introduction node. | ||
pub fn compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) { |
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.
Still, it does seem a bit strange that we're mutating the blinded path with a fn name that sounds like it could just as well be a straight getter.
@@ -213,6 +217,30 @@ impl BlindedPath { | |||
}, | |||
} | |||
} | |||
|
|||
/// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed | |||
/// short channel id from a channel in `network_graph` leading to the introduction node. |
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 have some kind of discussion of how this makes paths shorter but if a channel closes will invalidate it.
lightning/src/blinded_path/mod.rs
Outdated
if let Some((scid, channel_info)) = node_info | ||
.channels | ||
.iter() | ||
.find_map(|scid| network_graph.channel(*scid).map(|info| (*scid, info))) |
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.
Similar here, should we sort by size/age?
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, good catch. Using the block height from the scid as it seems the timestamp
in the update is really a counter specific to the channel.
.filter(|(_, peer)| peer.latest_features.supports_onion_messages()) | ||
.map(|(node_id, peer)| ForwardNode { | ||
node_id: *node_id, | ||
short_channel_id: peer.channel_by_id |
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.
Should we make setting this optional somehow? I feel like if I'm building a super long-term offer I may have a different preference from something being scanned right 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.
Yeah... arguably we shouldn't bother with it for reply paths, either. Just not sure exactly how we want to convey it through the MessageRouter
trait. Currently, the caller makes the decision for the penultimate hop using ForwardNode
, but when adding more hops the MessageRouter
makes the decision since it needs a NetworkGraph
to find more hops. Similarly for the introduction node.
So right now it's partly an implementation concern given you need a NetworkGraph
. I guess we can just add a bool parameter and it say it is best effort? Any other ideas?
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 see what you mean... if there's an obvious "default behavior" that stands out, we could have a separate method, e.g. create_long_term_blinded_paths
, or have a Config
struct. That way we could also have a config setting for compact offers vs offers that don't need to be QR-scanned, or privacy-oriented offers that want longer 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.
Opened #3080 with separate MessageRouter
methods, using compact paths for Offer::paths
and Refund::paths
and non-compact paths for onion message reply paths. Basically, the trait allows either for the caller to decide.
As for how this is exposed in ChannelManager
utilities, I'm not sure how we should handle short- vs long-lived offers. One thought was to chose the type of path based on the expiry. But for offers, the expiry is set by the user after the builder is returned and path already set. For refunds created via ChannelManager
, we require an expiration (even though the spec does not), though, so we could infer there.
Alternatives would be:
- making a special purpose
create_offer_builder
for long-lived offers - adding a parameter to
create_offer_builder
indicating if short- or long-lived - adding a
Option
al absolute expiry parameter tocreate_offer_builder
used to infer which type of path to create
Any preferences other alternatives?
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 good with whichever of those options you think is best!
@@ -450,7 +455,12 @@ where | |||
Err(()) | |||
} | |||
}, | |||
}?; | |||
for path in &mut paths { | |||
path.compact_introduction_node(&network_graph); |
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.
Similar here, can we make this optional on a per-offer/message basis?
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.
#3080 refactors MessageRouter
to have two different methods.
f3726a7
to
b295e98
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.
Oops, forgot to publish these comments.
lightning/src/blinded_path/mod.rs
Outdated
|
||
/// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed | ||
/// short channel id from a channel in `network_graph` leading to the introduction node. | ||
pub fn compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) { |
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.
Ok, added a use_
prefix. I can see how the docs make it less clear that compact
was a verb in the name.
lightning/src/blinded_path/mod.rs
Outdated
if let Some((scid, channel_info)) = node_info | ||
.channels | ||
.iter() | ||
.find_map(|scid| network_graph.channel(*scid).map(|info| (*scid, info))) |
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, good catch. Using the block height from the scid as it seems the timestamp
in the update is really a counter specific to the channel.
.filter(|(_, peer)| peer.latest_features.supports_onion_messages()) | ||
.map(|(node_id, peer)| ForwardNode { | ||
node_id: *node_id, | ||
short_channel_id: peer.channel_by_id |
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... arguably we shouldn't bother with it for reply paths, either. Just not sure exactly how we want to convey it through the MessageRouter
trait. Currently, the caller makes the decision for the penultimate hop using ForwardNode
, but when adding more hops the MessageRouter
makes the decision since it needs a NetworkGraph
to find more hops. Similarly for the introduction node.
So right now it's partly an implementation concern given you need a NetworkGraph
. I guess we can just add a bool parameter and it say it is best effort? Any other ideas?
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.
LGTM pending maybe making the compact encoding optional. Looks like it needs another rebase as well.
2dd24ed
to
7d85abd
Compare
Rebased now. Yeah, maybe best to do that in a follow-up as it may be a little more involved. Let me know if you have any thoughts on #3011 (comment). |
Feel free to squash and we can land this IMO. We should open an issue and block the next release on the followup. |
e7f5035
to
bb5dc03
Compare
Rebased and opened #3080. Looking for feedback on the |
@@ -171,7 +172,7 @@ impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref, | |||
fn create_blinded_paths< | |||
T: secp256k1::Signing + secp256k1::Verification | |||
> ( | |||
&self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>, | |||
&self, recipient: PublicKey, peers: Vec<message::ForwardNode>, secp_ctx: &Secp256k1<T>, |
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 going to split this into two methods, do we still need message::ForwardNode
? Can't one method take pubkeys and the other take scids?
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 alwasys need the pubkeys when creating the blinded path, so we'd need to either make a new struct or use a tuple. It's kinda nice having it use an Option
for short_channel_id
, though. It makes it easy in ChannelManager::create_blinded_path
to fallback to None
if a usable channel can't be found.
bb5dc03
to
f0d81ea
Compare
When sending an onion message to a blinded path, the short channel id between hops isn't need in each hop's encrypted_payload since it is not a payment. However, using the short channel id instead of the node id gives a more compact representation. Update BlindedPath::new_for_message to allow for this.
Instead of passing Vec<PublicKey> to MessageRouter::crate_blinded_path, pass Vec<ForwardNode>. This way callers can include a short_channel_id for a more compact BlindedPath encoding.
Add a method to BlindedPath that given a network graph will compact the IntroductionNode as the DirectedShortChannelId variant. Call this method from DefaultMessageRouter so that Offer paths use the compact representation (along with reply paths). This leaves payment paths in Bolt12Invoice using the NodeId variant, as the compact representation isn't as useful there.
f0d81ea
to
e4661fe
Compare
Added derives to |
Add support for creating a compact
BlindedPath
, which consists of:BlindedHop::encrypted_payload
IntroductionNode::DirectedShortChannelId
The first is accomplished by specifying SCIDs when calling
BlindedPath::new_for_message
using a newmessage::ForwardNode
struct. The second is through callingBlindedPath::use_compact_introduction_node
. Both are called byDefaultMessageRouter
.