Skip to content

Commit 3f15b85

Browse files
committed
Expose outbound SCID alias in ChannelDetails and use in routing
This supports routing outbound over 0-conf channels by utilizing the outbound SCID alias that we assign to all channels to refer to the selected channel when routing.
1 parent 96d80a7 commit 3f15b85

File tree

4 files changed

+30
-3
lines changed

4 files changed

+30
-3
lines changed

fuzz/src/router.rs

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

lightning/src/ln/channelmanager.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,16 @@ pub struct ChannelDetails {
12231223
/// [`inbound_scid_alias`]: Self::inbound_scid_alias
12241224
/// [`get_inbound_payment_scid`]: Self::get_inbound_payment_scid
12251225
pub short_channel_id: Option<u64>,
1226+
/// An optional [`short_channel_id`] alias for this channel, randomly generated by us and
1227+
/// usable in place of [`short_channel_id`] to reference the channel in outbound routes even if
1228+
/// the channel has not yet been confirmed (as long as [`confirmations_required`] is
1229+
/// `Some(0)`).
1230+
///
1231+
/// This will be `None` as long as the channel is not available for routing outbound payments.
1232+
///
1233+
/// [`short_channel_id`]: Self::short_channel_id
1234+
/// [`confirmations_required`]: Self::confirmations_required
1235+
pub outbound_scid_alias: Option<u64>,
12261236
/// An optional [`short_channel_id`] alias for this channel, randomly generated by our
12271237
/// counterparty and usable in place of [`short_channel_id`] in invoice route hints. Our
12281238
/// counterparty will recognize the alias provided here in place of the [`short_channel_id`]
@@ -1328,6 +1338,16 @@ impl ChannelDetails {
13281338
pub fn get_inbound_payment_scid(&self) -> Option<u64> {
13291339
self.inbound_scid_alias.or(self.short_channel_id)
13301340
}
1341+
1342+
/// Gets the current SCID which should be used to identify this channel for outbound payments.
1343+
/// This should be used in [`Route`]s to describe the first hop or in other contexts where
1344+
/// we're sending or forwarding a payment outbound over this channel.
1345+
///
1346+
/// This is either the [`ChannelDetails::short_channel_id`], if set, or the
1347+
/// [`ChannelDetails::outbound_scid_alias`]. See those for more information.
1348+
pub fn get_outbound_payment_scid(&self) -> Option<u64> {
1349+
self.short_channel_id.or(self.outbound_scid_alias)
1350+
}
13311351
}
13321352

13331353
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
@@ -1949,6 +1969,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
19491969
// `have_received_message` indicates that type negotiation has completed.
19501970
channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None },
19511971
short_channel_id: channel.get_short_channel_id(),
1972+
outbound_scid_alias: if channel.is_live() { Some(channel.outbound_scid_alias()) } else { None },
19521973
inbound_scid_alias: channel.latest_inbound_scid_alias(),
19531974
channel_value_satoshis: channel.get_value_satoshis(),
19541975
unspendable_punishment_reserve: to_self_reserve_satoshis,
@@ -6225,6 +6246,7 @@ impl_writeable_tlv_based!(ChannelDetails, {
62256246
(2, channel_id, required),
62266247
(3, channel_type, option),
62276248
(4, counterparty, required),
6249+
(5, outbound_scid_alias, option),
62286250
(6, funding_txo, option),
62296251
(8, short_channel_id, option),
62306252
(10, channel_value_satoshis, required),

lightning/src/ln/priv_short_conf_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,6 @@ fn test_simple_0_conf_channel() {
616616

617617
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
618618
assert_eq!(nodes[1].node.list_usable_channels().len(), 1);
619+
620+
send_payment(&nodes[0], &[&nodes[1]], 100_000);
619621
}

lightning/src/routing/router.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ enum CandidateRouteHop<'a> {
368368
impl<'a> CandidateRouteHop<'a> {
369369
fn short_channel_id(&self) -> u64 {
370370
match self {
371-
CandidateRouteHop::FirstHop { details } => details.short_channel_id.unwrap(),
371+
CandidateRouteHop::FirstHop { details } => details.get_outbound_payment_scid().unwrap(),
372372
CandidateRouteHop::PublicHop { short_channel_id, .. } => *short_channel_id,
373373
CandidateRouteHop::PrivateHop { hint } => hint.short_channel_id,
374374
}
@@ -766,7 +766,7 @@ where L::Target: Logger {
766766
HashMap::with_capacity(if first_hops.is_some() { first_hops.as_ref().unwrap().len() } else { 0 });
767767
if let Some(hops) = first_hops {
768768
for chan in hops {
769-
if chan.short_channel_id.is_none() {
769+
if chan.get_outbound_payment_scid().is_none() {
770770
panic!("first_hops should be filled in with usable channels, not pending ones");
771771
}
772772
if chan.counterparty.node_id == *our_node_pubkey {
@@ -1318,7 +1318,7 @@ where L::Target: Logger {
13181318
let mut features_set = false;
13191319
if let Some(first_channels) = first_hop_targets.get(&ordered_hops.last().unwrap().0.node_id) {
13201320
for details in first_channels {
1321-
if details.short_channel_id.unwrap() == ordered_hops.last().unwrap().0.candidate.short_channel_id() {
1321+
if details.get_outbound_payment_scid().unwrap() == ordered_hops.last().unwrap().0.candidate.short_channel_id() {
13221322
ordered_hops.last_mut().unwrap().1 = details.counterparty.features.to_context();
13231323
features_set = true;
13241324
break;
@@ -1727,6 +1727,7 @@ mod tests {
17271727
funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }),
17281728
channel_type: None,
17291729
short_channel_id,
1730+
outbound_scid_alias: None,
17301731
inbound_scid_alias: None,
17311732
channel_value_satoshis: 0,
17321733
user_channel_id: 0,
@@ -5450,6 +5451,7 @@ mod benches {
54505451
}),
54515452
channel_type: None,
54525453
short_channel_id: Some(1),
5454+
outbound_scid_alias: None,
54535455
inbound_scid_alias: None,
54545456
channel_value_satoshis: 10_000_000,
54555457
user_channel_id: 0,

0 commit comments

Comments
 (0)