mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-23 14:50:45 +01:00
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.
This commit is contained in:
parent
f54ebf78f6
commit
b2629afd88
5 changed files with 66 additions and 2 deletions
|
@ -216,6 +216,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
|
|||
},
|
||||
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
|
||||
short_channel_id: Some(scid),
|
||||
inbound_scid_alias: None,
|
||||
channel_value_satoshis: slice_to_be64(get_slice!(8)),
|
||||
user_channel_id: 0, inbound_capacity_msat: 0,
|
||||
unspendable_punishment_reserve: None,
|
||||
|
|
|
@ -65,7 +65,7 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
|
|||
|
||||
for hint in phantom_route_hints {
|
||||
for channel in &hint.channels {
|
||||
let short_channel_id = match channel.short_channel_id {
|
||||
let short_channel_id = match channel.get_inbound_payment_scid() {
|
||||
Some(id) => id,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -162,7 +162,7 @@ where
|
|||
let our_channels = channelmanager.list_usable_channels();
|
||||
let mut route_hints = vec![];
|
||||
for channel in our_channels {
|
||||
let short_channel_id = match channel.short_channel_id {
|
||||
let short_channel_id = match channel.get_inbound_payment_scid() {
|
||||
Some(id) => id,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -313,6 +313,13 @@ mod test {
|
|||
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
|
||||
assert_eq!(invoice.description(), InvoiceDescription::Direct(&Description("test".to_string())));
|
||||
|
||||
// Invoice SCIDs should always use inbound SCID aliases over the real channel ID, if one is
|
||||
// available.
|
||||
assert_eq!(invoice.route_hints().len(), 1);
|
||||
assert_eq!(invoice.route_hints()[0].0.len(), 1);
|
||||
assert_eq!(invoice.route_hints()[0].0[0].short_channel_id,
|
||||
nodes[1].node.list_usable_channels()[0].inbound_scid_alias.unwrap());
|
||||
|
||||
let payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key())
|
||||
.with_features(invoice.features().unwrap().clone())
|
||||
.with_route_hints(invoice.route_hints());
|
||||
|
|
|
@ -695,6 +695,13 @@ pub(super) struct Channel<Signer: Sign> {
|
|||
|
||||
/// This channel's type, as negotiated during channel open
|
||||
channel_type: ChannelTypeFeatures,
|
||||
|
||||
// Our counterparty can offer us SCID aliases which they will map to this channel when routing
|
||||
// outbound payments. These can be used in invoice route hints to avoid explicitly revealing
|
||||
// the channel's funding UTXO.
|
||||
// We only bother storing the most recent SCID alias at any time, though our counterparty has
|
||||
// to store all of them.
|
||||
latest_inbound_scid_alias: Option<u64>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, fuzzing))]
|
||||
|
@ -947,6 +954,8 @@ impl<Signer: Sign> Channel<Signer> {
|
|||
|
||||
workaround_lnd_bug_4006: None,
|
||||
|
||||
latest_inbound_scid_alias: None,
|
||||
|
||||
#[cfg(any(test, fuzzing))]
|
||||
historical_inbound_htlc_fulfills: HashSet::new(),
|
||||
|
||||
|
@ -1252,6 +1261,8 @@ impl<Signer: Sign> Channel<Signer> {
|
|||
|
||||
workaround_lnd_bug_4006: None,
|
||||
|
||||
latest_inbound_scid_alias: None,
|
||||
|
||||
#[cfg(any(test, fuzzing))]
|
||||
historical_inbound_htlc_fulfills: HashSet::new(),
|
||||
|
||||
|
@ -2151,6 +2162,15 @@ impl<Signer: Sign> Channel<Signer> {
|
|||
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()));
|
||||
}
|
||||
|
||||
if let Some(scid_alias) = msg.short_channel_id_alias {
|
||||
if Some(scid_alias) != self.short_channel_id {
|
||||
// The scid alias provided can be used to route payments *from* our counterparty,
|
||||
// i.e. can be used for inbound payments and provided in invoices, but is not used
|
||||
// when routing outbound payments.
|
||||
self.latest_inbound_scid_alias = Some(scid_alias);
|
||||
}
|
||||
}
|
||||
|
||||
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
|
||||
|
||||
if non_shutdown_state == ChannelState::FundingSent as u32 {
|
||||
|
@ -4198,6 +4218,11 @@ impl<Signer: Sign> Channel<Signer> {
|
|||
self.short_channel_id
|
||||
}
|
||||
|
||||
/// Allowed in any state (including after shutdown)
|
||||
pub fn latest_inbound_scid_alias(&self) -> Option<u64> {
|
||||
self.latest_inbound_scid_alias
|
||||
}
|
||||
|
||||
/// Returns the funding_txo we either got from our peer, or were given by
|
||||
/// get_outbound_funding_created.
|
||||
pub fn get_funding_txo(&self) -> Option<OutPoint> {
|
||||
|
@ -5769,6 +5794,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
|
|||
(13, self.channel_creation_height, required),
|
||||
(15, preimages, vec_type),
|
||||
(17, self.announcement_sigs_state, required),
|
||||
(19, self.latest_inbound_scid_alias, option),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -6024,6 +6050,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
|
|||
// If we read an old Channel, for simplicity we just treat it as "we never sent an
|
||||
// AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
|
||||
let mut announcement_sigs_state = Some(AnnouncementSigsState::NotSent);
|
||||
let mut latest_inbound_scid_alias = None;
|
||||
|
||||
read_tlv_fields!(reader, {
|
||||
(0, announcement_sigs, option),
|
||||
|
@ -6039,6 +6066,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
|
|||
(13, channel_creation_height, option),
|
||||
(15, preimages_opt, vec_type),
|
||||
(17, announcement_sigs_state, option),
|
||||
(19, latest_inbound_scid_alias, option),
|
||||
});
|
||||
|
||||
if let Some(preimages) = preimages_opt {
|
||||
|
@ -6173,6 +6201,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
|
|||
|
||||
workaround_lnd_bug_4006: None,
|
||||
|
||||
latest_inbound_scid_alias,
|
||||
|
||||
#[cfg(any(test, fuzzing))]
|
||||
historical_inbound_htlc_fulfills,
|
||||
|
||||
|
|
|
@ -1188,7 +1188,20 @@ pub struct ChannelDetails {
|
|||
pub funding_txo: Option<OutPoint>,
|
||||
/// The position of the funding transaction in the chain. None if the funding transaction has
|
||||
/// not yet been confirmed and the channel fully opened.
|
||||
///
|
||||
/// Note that if [`inbound_scid_alias`] is set, it must be used for invoices and inbound
|
||||
/// payments instead of this. See [`get_inbound_payment_scid`].
|
||||
///
|
||||
/// [`inbound_scid_alias`]: Self::inbound_scid_alias
|
||||
/// [`get_inbound_payment_scid`]: Self::get_inbound_payment_scid
|
||||
pub short_channel_id: Option<u64>,
|
||||
/// An optional [`short_channel_id`] alias for this channel, randomly generated by our
|
||||
/// counterparty and usable in place of [`short_channel_id`] in invoice route hints. Our
|
||||
/// counterparty will recognize the alias provided here in place of the [`short_channel_id`]
|
||||
/// when they see a payment to be routed to us.
|
||||
///
|
||||
/// [`short_channel_id`]: Self::short_channel_id
|
||||
pub inbound_scid_alias: Option<u64>,
|
||||
/// The value, in satoshis, of this channel as appears in the funding output
|
||||
pub channel_value_satoshis: u64,
|
||||
/// The value, in satoshis, that must always be held in the channel for us. This value ensures
|
||||
|
@ -1274,6 +1287,15 @@ pub struct ChannelDetails {
|
|||
pub is_public: bool,
|
||||
}
|
||||
|
||||
impl ChannelDetails {
|
||||
/// Gets the SCID which should be used to identify this channel for inbound payments. This
|
||||
/// should be used for providing invoice hints or in any other context where our counterparty
|
||||
/// will forward a payment to us.
|
||||
pub fn get_inbound_payment_scid(&self) -> Option<u64> {
|
||||
self.inbound_scid_alias.or(self.short_channel_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
|
||||
/// Err() type describing which state the payment is in, see the description of individual enum
|
||||
/// states for more.
|
||||
|
@ -1833,6 +1855,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
|||
},
|
||||
funding_txo: channel.get_funding_txo(),
|
||||
short_channel_id: channel.get_short_channel_id(),
|
||||
inbound_scid_alias: channel.latest_inbound_scid_alias(),
|
||||
channel_value_satoshis: channel.get_value_satoshis(),
|
||||
unspendable_punishment_reserve: to_self_reserve_satoshis,
|
||||
balance_msat,
|
||||
|
@ -5973,6 +5996,7 @@ impl_writeable_tlv_based!(ChannelCounterparty, {
|
|||
});
|
||||
|
||||
impl_writeable_tlv_based!(ChannelDetails, {
|
||||
(1, inbound_scid_alias, option),
|
||||
(2, channel_id, required),
|
||||
(4, counterparty, required),
|
||||
(6, funding_txo, option),
|
||||
|
|
|
@ -1578,6 +1578,7 @@ mod tests {
|
|||
},
|
||||
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
|
||||
short_channel_id,
|
||||
inbound_scid_alias: None,
|
||||
channel_value_satoshis: 0,
|
||||
user_channel_id: 0,
|
||||
balance_msat: 0,
|
||||
|
@ -5101,6 +5102,7 @@ mod benches {
|
|||
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0
|
||||
}),
|
||||
short_channel_id: Some(1),
|
||||
inbound_scid_alias: None,
|
||||
channel_value_satoshis: 10_000_000,
|
||||
user_channel_id: 0,
|
||||
balance_msat: 10_000_000,
|
||||
|
|
Loading…
Add table
Reference in a new issue