Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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" + '
Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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('^' + ".*" + ' Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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('^' + ".*" + ' Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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" + ' Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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('^' + ".*" + ' Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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('^' + ".*" + ' Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard
, '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); } })(); })(); Implement the SCIDAlias Channel Type and provide SCID Privacy by TheBlueMatt · Pull Request #1351 · lightningdevkit/rust-lightning · GitHub
Skip to content

Implement the SCIDAlias Channel Type and provide SCID Privacy - #1351

Merged
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy
Mar 28, 2022
Merged

Implement the SCIDAlias Channel Type and provide SCID Privacy#1351
TheBlueMatt merged 9 commits into
lightningdevkit:mainfrom
TheBlueMatt:2022-03-scid-privacy

Conversation

@TheBlueMatt

Copy link
Copy Markdown
Collaborator

This is based on #1311 and implements the SCIDAlias channel type as well as ensures we don't leak "real" SCIDs via HTLC failures (as pointed out by Val at #1311 (comment))

@TheBlueMattTheBlueMatt mentioned this pull request Mar 8, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch from 4c2a120 to e5b5bdbCompareMarch 8, 2022 22:00
@codecov-commenter

ghost commented Mar 8, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1351 (4d9a5c2) into main (ca163c3) will increase coverage by 0.82%.
The diff coverage is 97.79%.

❗ Current head 4d9a5c2 differs from pull request most recent head 952cee4. Consider uploading reports for the commit 952cee4 to get more accurate results

@@ Coverage Diff @@## main #1351 +/- ##
==========================================
+ Coverage 90.65% 91.47% +0.82% 
==========================================
Files 73 73 Lines 40462 48497 +8035 Branches 0 48497 +48497 ==========================================
+ Hits 36682 44365 +7683 - Misses 3780 4132 +352 
Impacted FilesCoverage Δ
lightning/src/ln/onion_route_tests.rs97.62% <ø> (ø)
lightning/src/util/config.rs45.83% <0.00%> (-0.98%)⬇️
lightning/src/util/ser.rs91.46% <ø> (ø)
lightning/src/ln/channel.rs90.39% <96.15%> (+1.18%)⬆️
lightning/src/ln/channelmanager.rs87.90% <97.00%> (+3.12%)⬆️
lightning/src/ln/priv_short_conf_tests.rs97.83% <98.88%> (+0.99%)⬆️
lightning/src/ln/features.rs99.44% <100.00%> (+1.13%)⬆️
lightning/src/ln/functional_test_utils.rs95.54% <100.00%> (ø)
lightning/src/routing/router.rs93.21% <100.00%> (+0.81%)⬆️
lightning/src/util/events.rs31.14% <100.00%> (-2.31%)⬇️
... and 17 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ca163c3...952cee4. Read the comment docs.

@TheBlueMatt

ghost commented Mar 10, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Note first commit is #1331, which we still depend on here.

@TheBlueMattTheBlueMatt added this to the 0.0.106 milestone Mar 10, 2022
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 2 times, most recently from 3bf9cea to ff0dce9CompareMarch 10, 2022 17:38
@jkczyz
jkczyz self-requested a review March 10, 2022 21:33
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_alias: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

First, I would say it's more a ChannelConfig flag as it's related to channel metada and not HTLC flow or channel format itself ? Though reading the types of configs comments I'm not sure if we have that strong a reasoning to sort config flags.

Second, do you think we should introduce some config sanitization to avoid invalid flags to be set up and thus detect buggy config ? In that present case, we would disallow negotiate_scid_alias if announced_channel is true, I think ?

edit: I see you do such sanitization in get_initial_channel_type maybe you could log a warning message for the incompatible combination ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I believe we'd like to move towards ChannelConfig being only update-able fields (ie fees and such), see-also #1270. As for sanitation, yea, we probably should, historically we've just ignored nonsense settings, which we should document/do here as well.

let scid_pref = if chan.should_announce() {
chan.get_short_channel_id().or(chan.latest_inbound_scid_alias())
} else {
chan.latest_inbound_scid_alias().or(chan.get_short_channel_id())

ghostMar 11, 2022

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just to understand better, let's say the HTLC routing topology is Alice -> Bob -> Caroll, here we're returning a error date for the failure on Bob to Caroll as reported by Bob ? If so, it sounds counter-intuitive to use latest_inbound_scid_alias as it's discovered by Bob from Caroll's funding_locked iiuc and never announced by Alice by a routing hint ?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

No, the channel here would be the channel from Alice to Bob, note the comment in the docs:

	/// This is for failures on the channel on which the HTLC was *received*, not failures
/// forwarding

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

Overall looks pretty good. Need to take a more thorough look at the tests and when failing HTLCs.

Comment threadlightning/src/util/events.rs Outdated
funding_satoshis: u64,
/// Our starting balance in the channel if the request is accepted, in milli-satoshi.
push_msat: u64,
/// The features which this channel will operate with. If you reject the channel, a

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.

s/which/that

Rule of thumb: Use "that" if what follows restricts the preceding phrase and hence removing the clause would change its meaning. Use "which" if the clause can be removed without changing the meaning.

Comment threadlightning/src/ln/channel.rs
Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
/// requires that our counterparty only relay HTLCs to us which use the channel's SCID alias.
///
/// If this option is set, channels may be created which will not be readable by LDK versions
/// prior to 0.0.106, causing [`ChannelManager`]'s read method to return a

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.

s/[ChannelManager]'s read method/[ChannelManager::read]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Sadly the link is broken if I do that since its through a trait - I can do it without [], or I can leave it as is, which do you prefer?

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.

Fine to keep it as is.

Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/util/config.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {
if !self.is_outbound() || self.channel_state != ChannelState::OurInitSent as u32 { return Err(()); }

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.

Hmmm... this check may be more suitable at the call site. That way it is clear the error message is in response to an open_channel message. Though, I suppose you wouldn't want this called when in a different state. Maybe it would simpler to inline the method in handle_error?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmmmm, I really prefer to keep as much channel state machine logic in channel.rs as possible. In general we've failed at this increasingly, but if I ever find time I'm gonna try to push a chunk back down. channelmanager should just be for inter-channel stuff, never have any real knowledge of channel's state machine transitions, though it has to sometimes ask about the current state.

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.

Ah, I see - good point! I guess it seems that ChannelManager::handle_event has state machine logic, though, because it assumes the error message is a response to open_channel. Would it make sense to add a handle_error method to Channel, which ChannelManager could delegate to? That would in turn have this logic to determine whether advance_channel_type_pref should be called or something else in the future depending on the channel state. I suppose it would need to return an event for ChannelManager to enqueue instead of assuming it is SendOpenChannel.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

because it assumes the error message is a response to open_channel.

Heh, that's why i put the state check in channel.rs that way channelmanager doesn't really know what the error is in response to, it just tries and lets channel figure it out. I'm gonna rename advance_channel_type_pref to maybe_handle_error_without_close to make it "feel" more generic.

Unless you feel strongly I'm not gonna bother changing its return type, though, currently all of the channel/channelmanager bounday has chanellmanger "know" what type of message is being sent, cause its enforced by the type-checker. I agree in the future we should move some of those to events, but that's also a larger refactor.

Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

Is this subject to change? Seems you thought 50 was the actual desired feature bit: https://github.com/lightning/bolts/pull/910/files#r807405646

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, yea, somewhat unclear, I guess we have to wait for this to get merged....

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.

To be clear, are we waiting on clarification on this?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Oh, oops, sorry, no, so the 48/50 thing is the zero_conf feature, not the SCID feature, the SCID feature is consistently 46/47 everywhere in the current PR.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

Seems this can't fail and can just return a ChannelUpdate instead of Result?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, maybe we should check state before returning actually? I guess if the channel isn't live we shouldn't even be there, but in any cast it doesn't cost anything to return the Result, no? its just used in one place.

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment on lines +3746 to +3752
let enc = if desired_err_code == 0x1000 | 20 {
let mut res = Vec::new();
// TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
res.extend_from_slice(&byte_utils::be16_to_array(0));
res.extend_from_slice(&upd.encode_with_len());
res
} else { upd.encode_with_len() };

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.

Think this'd be slightly cleaner as:

let mut res = Vec::with_capacity(8 + 128);
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
if error_code == 0x1000 | 20 {
res.extend_from_slice(&byte_utils::be16_to_array(0));
}
res.extend_from_slice(&upd.encode_with_len()[..]);

taken from 694ef1e

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I wanted to avoid the hard-coded length upper bound assumption, but I can use serialized_length, too, I suppose.

@@ -4466,10 +4524,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
// channel_update here if the channel is not public, i.e. we're not sending an
// announcement_signatures.
log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id()));

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.

Maybe move the log to after Ok, similar below

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, it should always succeed, and is kinda nice to always log - if we don't see the later generation logs in the get_channel_update* methods we know something is wrong.


self.get_channel_update_for_onion(short_channel_id, chan)
}
fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<Signer>) -> Result<msgs::ChannelUpdate, LightningError> {

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.

My thinking is it's cleaner to not return a result if it's not necessary. Fine if the check is desired though

Comment threadlightning/src/ln/channel.rs Outdated
/// If we receive an error message, it may only be a rejection of the channel type we tried,
/// not of our ability to open any channel at all. Thus, on error, we should first call this
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
pub(crate) fn advance_channel_type_pref(&mut self, chain_hash: BlockHash) -> Result<msgs::OpenChannel, ()> {

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.

Feel like downgrade_channel_type would be more accurate

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, is it strictly a "downgrade" always, though? I guess my mental model here was we have a list of channel types we are willing to use, and we're iterating through that list until we find one that works.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/functional_test_utils.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channel.rs Outdated
Comment on lines +1045 to +1047
let mut allowed_type = ChannelTypeFeatures::only_static_remote_key();
if *channel_type != allowed_type {
allowed_type.set_scid_alias_required();

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.

Given the deserialization issue for older versions of LDK, should we also refuse inbound channels with scid_alias_required unless the config is set?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Yea, I was trying to avoid adding an explicit config for it by letting users do a generic "check channel type flags" thing, though I admit its definitely forcing users to jump through quite a few hoops for something that they may want. It'll need calling out in the release notes either way, just don't know how much we want to complexify the config objects. We could also complexify them and remove the new option in the next release, but doing the manual accept hops isn't crazy either. I dunno.

Comment threadlightning/src/ln/priv_short_conf_tests.rs
@TheBlueMatt
TheBlueMattforce-pushed the 2022-03-scid-privacy branch 3 times, most recently from c2e88e8 to d0e8402CompareMarch 17, 2022 21:23
Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs
Comment threadlightning/src/ln/channelmanager.rs Outdated
Comment threadlightning/src/ln/features.rs Outdated
define_feature!(45, ChannelType, [InitContext, NodeContext],
"Feature flags for `option_channel_type`.", set_channel_type_optional,
set_channel_type_required, supports_channel_type, requires_channel_type);
define_feature!(47, SCIDAlias, [InitContext, NodeContext, ChannelTypeContext],

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.

To be clear, are we waiting on clarification on this?

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

Looks good, test coverage sounds correct.

Comment threadlightning/src/ln/channel.rs Outdated
Comment threadlightning/src/ln/channelmanager.rs Outdated
// Leave channel updates as None for private channels.
let chan_update_opt = if chan.should_announce() {
Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None };
let chan_update_opt = self.get_channel_update_for_broadcast(chan).ok();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you should write better the rational for why we're using get_channel_update_broadcast instead of unicast. I didn't get the why at first read.

Something like "SCID alias aims to mask the real channel SCID from the payment sender. If we return the real channel SCID in a channel update error message, it would allow a payment sender to deanonymize the alias by triggering HTLC failures on the routing fees or HTLC minimum amount".

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good catch, but this doesn't need a comment, this is just wrong!

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Also updated the test to hit this case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought if short_channel_id is the real scid for a private channel, we still want to leave the update as None?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

We do - the chan.get_channel_type().supports_scid_alias() && *short_channel_id != chan.outbound_scid_alias() check below the chan_update_opt get breaks with None, dropping the chan_update_opt. For clarity I moved the get_channel_update_for_onion call down a few lines.

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.

Missing something here -- if we're attempting to forward over a private channel without an alias, and we break on e.g. if !chan.is_live() 10 lines down, won't we include the private channel update with the current code?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Hmm, so the SCIDAlias feature is supposed to be the "never, ever, ever tell anyone the real SCID" flag (maybe we should rename it scid_privacy in LDK?). I guess in principle we could treat any private channel as an SCIDPrivacy/SCIDAlias channel for the purposes of channel_update generation, but I think eventually after people upgrade a private channel without the flag is rare/indicates some strange use-case where they're gonna use the real SCID for something.

Comment threadlightning/src/ln/channel.rs
// should NOT reveal the existence or non-existence of a private channel if
// we don't allow forwards outbound over them.
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Likely before this PR, though not sure if there is test coverage for that.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

When I comment this line out I get failures in ln::priv_short_conf_tests::test_priv_forwarding_rejection and ln::priv_short_conf_tests::test_scid_alias_on_pub_channel

@valentinewallace

ghost commented Mar 22, 2022

Copy link
Copy Markdown
Contributor

Left one question #1351 (comment) and CI's sad. I'm pretty much ACK otherwise

valentinewallace
valentinewallace previously approved these changes Mar 23, 2022
(0x4000|10, Vec::new())
}
}

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.

nit: extra line

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Test coverage looks good. Only outstanding comment is #1351 (comment).

@jkczyz

ghost commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

You can do 0conf without scid_alias, so its not a prereq.

FWIW, the bolt has it as a dependency.

@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

FWIW, the bolt has it as a dependency.

Hmm, that's confusing, I believe that is talking about it in the init flags, the part talking about channel types has no such indication - https://github.com/lightning/bolts/pull/910/files#diff-ed04ca2c673fd6aabde69389511fa9ee60cb44d6b2ef6c88b549ffaa753d6afeR216

@valentinewallace

ghost commented Mar 24, 2022

Copy link
Copy Markdown
Contributor

Would you disagree with naming the feature scid_privacy and leaving everything else as scid_alias? THat's what I was thinking but I don't feel super duper strongly about it.

Yeah, there and maybe the config option I'd be fine with changing.

SGTM

Comment threadlightning/src/util/events.rs Outdated
@TheBlueMatt

ghost commented Mar 24, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Squashed down the existing fixup commits, added some new ones to address Jeff's last comment and rename the scid_privacy feature.

Comment threadlightning/src/ln/features.rs Outdated
Comment threadlightning/src/util/events.rs Outdated
Comment threadlightning/src/ln/channel.rs Outdated
@valentinewallace

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

I'm ACK after Jeff's comments are addressed

@TheBlueMatt

ghost commented Mar 25, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Addressed all the comments, let me know if I should squash.

@jkczyz

ghost commented Mar 25, 2022

Copy link
Copy Markdown
Contributor

Addressed all the comments, let me know if I should squash.

Yes, please squash

Matt Corallo added 8 commits March 27, 2022 17:12
1.51 (and other earlier versions of `rustc`) appear to refuse to
accept our documentation links due to a bogus failure to resolve
`ChannelTypeFeatures::supports_scid_privacy`.
As we add new supported channel types, inbound channels which use
new features may cause backwards-compatibility issues for clients.
If a new channel is opened using new features while a client still
wishes to ensure support for downgrading to a previous version of
LDK, that new channel may cause the `ChannelManager` to fail
deserialization due to unsupported feature flags.
By exposing the channel type flags to the user in channel requests,
users wishing to support downgrading to previous versions of LDK
can reject channels which use channel features which previous
versions of LDK do not understand.
This does not, however, ever send the scid_alias feature bit for
outgoing channels, as that would cause the immediately prior
version of LDK to be unable to read channel data.
Because negotiating `scid_alias` for all of our channels will cause
us to create channels which LDK versions prior to 0.0.106 do not
understand, we disable `scid_alias` negotiation by default.
This reduces unwraps in channelmanager by a good bit, providing
robustness for the upcoming 0conf changes which allow SCIDs to be
missing after a channel is in use, making
`get_channel_update_for_unicast` more fallible.
This also serves as a useful refactor for the next commit,
consolidating the channel_update creation sites which are changed
in the next commit.
When we fail an HTLC which was destined for a channel that the HTLC
sender didn't know the real SCID for, we should ensure we continue
to use the alias in the channel_update we provide them. Otherwise
we will leak the channel's real SCID to HTLC senders.
There's not a lot of reason to keep it given its used in one place
outside of tests, and this lets us clean up some of the byte_utils
calls that are still lying around.
@TheBlueMatt

ghost commented Mar 27, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Pushed an additional commit at the start to bump the CI rustc version in check_commits - for some reason older rustcs refuse a perfectly fine doc link.

ariard
ariard previously approved these changes Mar 28, 2022

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

ACK c47acd7

(Good with the scid_privacy renaming)

///
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
/// [`DecodeError:InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
pub negotiate_scid_privacy: bool,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: You can precise we only store for now the latest announced SCID alias by our counterparty. That's an implementation details that user might be interested to know (e.g if they would like to rotate scid alias for each invoice)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Good point, but feel like that belongs on ChannelDetails::inbound_scid_alias and ChannelDetails::get_inbound_payment_scid

@TheBlueMatt

ghost commented Mar 28, 2022

Copy link
Copy Markdown
CollaboratorAuthor

Added an extra commit with more docs (the relevant code is already upstream).

@TheBlueMatt
TheBlueMatt merged commit 7671ae5 into lightningdevkit:mainMar 28, 2022
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants

@TheBlueMatt@codecov-commenter@valentinewallace@jkczyz@ariard