Skip to content

Commit cf37b70

Browse files
TheBlueMatttnull
authored andcommitted
Track SCID aliases from our counterparty and use them in invoices
New `funding_locked` messages can include SCID aliases which our counterparty will recognize as "ours" for the purposes of relaying transactions to us. This avoids telling the world about our on-chain transactions every time we want to receive a payment, and will allow for receiving payments before the funding transaction appears on-chain. Here we store the new SCID aliases and use them in invoices instead of he "standard" SCIDs.
1 parent b09ba1f commit cf37b70

File tree

5 files changed

+66
-2
lines changed

5 files changed

+66
-2
lines changed

fuzz/src/router.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
216216
},
217217
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
218218
short_channel_id: Some(scid),
219+
inbound_scid_alias: None,
219220
channel_value_satoshis: slice_to_be64(get_slice!(8)),
220221
user_channel_id: 0, inbound_capacity_msat: 0,
221222
unspendable_punishment_reserve: None,

lightning-invoice/src/utils.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
6868

6969
for hint in phantom_route_hints {
7070
for channel in &hint.channels {
71-
let short_channel_id = match channel.short_channel_id {
71+
let short_channel_id = match channel.get_inbound_payment_scid() {
7272
Some(id) => id,
7373
None => continue,
7474
};
@@ -165,7 +165,7 @@ where
165165
let our_channels = channelmanager.list_usable_channels();
166166
let mut route_hints = vec![];
167167
for channel in our_channels {
168-
let short_channel_id = match channel.short_channel_id {
168+
let short_channel_id = match channel.get_inbound_payment_scid() {
169169
Some(id) => id,
170170
None => continue,
171171
};
@@ -325,6 +325,13 @@ mod test {
325325
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
326326
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
327327

328+
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
329+
// available.
330+
assert_eq!(invoice.route_hints().len(), 1);
331+
assert_eq!(invoice.route_hints()[0].0.len(), 1);
332+
assert_eq!(invoice.route_hints()[0].0[0].short_channel_id,
333+
nodes[1].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
334+
328335
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
329336
.with_features(invoice.features().unwrap().clone())
330337
.with_route_hints(invoice.route_hints());

lightning/src/ln/channel.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,13 @@ pub(super) struct Channel<Signer: Sign> {
695695

696696
/// This channel's type, as negotiated during channel open
697697
channel_type: ChannelTypeFeatures,
698+
699+
// Our counterparty can offer us SCID aliases which they will map to this channel when routing
700+
// outbound payments. These can be used in invoice route hints to avoid explicitly revealing
701+
// the channel's funding UTXO.
702+
// We only bother storing the most recent SCID alias at any time, though our counterparty has
703+
// to store all of them.
704+
latest_inbound_scid_alias: Option<u64>,
698705
}
699706

700707
#[cfg(any(test, fuzzing))]
@@ -947,6 +954,8 @@ impl<Signer: Sign> Channel<Signer> {
947954

948955
workaround_lnd_bug_4006: None,
949956

957+
latest_inbound_scid_alias: None,
958+
950959
#[cfg(any(test, fuzzing))]
951960
historical_inbound_htlc_fulfills: HashSet::new(),
952961

@@ -1252,6 +1261,8 @@ impl<Signer: Sign> Channel<Signer> {
12521261

12531262
workaround_lnd_bug_4006: None,
12541263

1264+
latest_inbound_scid_alias: None,
1265+
12551266
#[cfg(any(test, fuzzing))]
12561267
historical_inbound_htlc_fulfills: HashSet::new(),
12571268

@@ -2151,6 +2162,15 @@ impl<Signer: Sign> Channel<Signer> {
21512162
return Err(ChannelError::Ignore("Peer sent funding_locked when we needed a channel_reestablish. The peer is likely lnd, see https://github.com/lightningnetwork/lnd/issues/4006".to_owned()));
21522163
}
21532164

2165+
if let Some(scid_alias) = msg.short_channel_id_alias {
2166+
if Some(scid_alias) != self.short_channel_id {
2167+
// The scid alias provided can be used to route payments *from* our counterparty,
2168+
// i.e. can be used for inbound payments and provided in invoices, but is not used
2169+
// when routing outbound payments.
2170+
self.latest_inbound_scid_alias = Some(scid_alias);
2171+
}
2172+
}
2173+
21542174
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
21552175

21562176
if non_shutdown_state == ChannelState::FundingSent as u32 {
@@ -4198,6 +4218,11 @@ impl<Signer: Sign> Channel<Signer> {
41984218
self.short_channel_id
41994219
}
42004220

4221+
/// Allowed in any state (including after shutdown)
4222+
pub fn latest_inbound_scid_alias(&self) -> Option<u64> {
4223+
self.latest_inbound_scid_alias
4224+
}
4225+
42014226
/// Returns the funding_txo we either got from our peer, or were given by
42024227
/// get_outbound_funding_created.
42034228
pub fn get_funding_txo(&self) -> Option<OutPoint> {
@@ -5769,6 +5794,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
57695794
(13, self.channel_creation_height, required),
57705795
(15, preimages, vec_type),
57715796
(17, self.announcement_sigs_state, required),
5797+
(19, self.latest_inbound_scid_alias, option),
57725798
});
57735799

57745800
Ok(())
@@ -6024,6 +6050,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
60246050
// If we read an old Channel, for simplicity we just treat it as "we never sent an
60256051
// AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
60266052
let mut announcement_sigs_state = Some(AnnouncementSigsState::NotSent);
6053+
let mut latest_inbound_scid_alias = None;
60276054

60286055
read_tlv_fields!(reader, {
60296056
(0, announcement_sigs, option),
@@ -6039,6 +6066,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
60396066
(13, channel_creation_height, option),
60406067
(15, preimages_opt, vec_type),
60416068
(17, announcement_sigs_state, option),
6069+
(19, latest_inbound_scid_alias, option),
60426070
});
60436071

60446072
if let Some(preimages) = preimages_opt {
@@ -6173,6 +6201,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
61736201

61746202
workaround_lnd_bug_4006: None,
61756203

6204+
latest_inbound_scid_alias,
6205+
61766206
#[cfg(any(test, fuzzing))]
61776207
historical_inbound_htlc_fulfills,
61786208

lightning/src/ln/channelmanager.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,20 @@ pub struct ChannelDetails {
11881188
pub funding_txo: Option<OutPoint>,
11891189
/// The position of the funding transaction in the chain. None if the funding transaction has
11901190
/// not yet been confirmed and the channel fully opened.
1191+
///
1192+
/// Note that if [`inbound_scid_alias`] is set, it must be used for invoices and inbound
1193+
/// payments instead of this. See [`get_inbound_payment_scid`].
1194+
///
1195+
/// [`inbound_scid_alias`]: Self::inbound_scid_alias
1196+
/// [`get_inbound_payment_scid`]: Self::get_inbound_payment_scid
11911197
pub short_channel_id: Option<u64>,
1198+
/// An optional [`short_channel_id`] alias for this channel, randomly generated by our
1199+
/// counterparty and usable in place of [`short_channel_id`] in invoice route hints. Our
1200+
/// counterparty will recognize the alias provided here in place of the [`short_channel_id`]
1201+
/// when they see a payment to be routed to us.
1202+
///
1203+
/// [`short_channel_id`]: Self::short_channel_id
1204+
pub inbound_scid_alias: Option<u64>,
11921205
/// The value, in satoshis, of this channel as appears in the funding output
11931206
pub channel_value_satoshis: u64,
11941207
/// The value, in satoshis, that must always be held in the channel for us. This value ensures
@@ -1274,6 +1287,15 @@ pub struct ChannelDetails {
12741287
pub is_public: bool,
12751288
}
12761289

1290+
impl ChannelDetails {
1291+
/// Gets the SCID which should be used to identify this channel for inbound payments. This
1292+
/// should be used for providing invoice hints or in any other context where our counterparty
1293+
/// will forward a payment to us.
1294+
pub fn get_inbound_payment_scid(&self) -> Option<u64> {
1295+
self.inbound_scid_alias.or(self.short_channel_id)
1296+
}
1297+
}
1298+
12771299
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
12781300
/// Err() type describing which state the payment is in, see the description of individual enum
12791301
/// states for more.
@@ -1833,6 +1855,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
18331855
},
18341856
funding_txo: channel.get_funding_txo(),
18351857
short_channel_id: channel.get_short_channel_id(),
1858+
inbound_scid_alias: channel.latest_inbound_scid_alias(),
18361859
channel_value_satoshis: channel.get_value_satoshis(),
18371860
unspendable_punishment_reserve: to_self_reserve_satoshis,
18381861
balance_msat,
@@ -5975,6 +5998,7 @@ impl_writeable_tlv_based!(ChannelCounterparty, {
59755998
});
59765999

59776000
impl_writeable_tlv_based!(ChannelDetails, {
6001+
(1, inbound_scid_alias, option),
59786002
(2, channel_id, required),
59796003
(4, counterparty, required),
59806004
(6, funding_txo, option),

lightning/src/routing/router.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,7 @@ mod tests {
16711671
},
16721672
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
16731673
short_channel_id,
1674+
inbound_scid_alias: None,
16741675
channel_value_satoshis: 0,
16751676
user_channel_id: 0,
16761677
balance_msat: 0,
@@ -5365,6 +5366,7 @@ mod benches {
53655366
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
53665367
}),
53675368
short_channel_id: Some(1),
5369+
inbound_scid_alias: None,
53685370
channel_value_satoshis: 10_000_000,
53695371
user_channel_id: 0,
53705372
balance_msat: 10_000_000,

0 commit comments

Comments
 (0)