Skip to content

Require directional updates for a DirectionalChannelInfo #1815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 16 additions & 53 deletions lightning/src/routing/gossip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ impl ChannelInfo {
return None;
}
};
Some((DirectedChannelInfo::new(self, direction), source))
direction.map(|dir| (DirectedChannelInfo::new(self, dir), source))
}

/// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
Expand All @@ -765,7 +765,7 @@ impl ChannelInfo {
return None;
}
};
Some((DirectedChannelInfo::new(self, direction), target))
direction.map(|dir| (DirectedChannelInfo::new(self, dir), target))
}

/// Returns a [`ChannelUpdateInfo`] based on the direction implied by the channel_flag.
Expand Down Expand Up @@ -860,29 +860,23 @@ impl Readable for ChannelInfo {
#[derive(Clone)]
pub struct DirectedChannelInfo<'a> {
channel: &'a ChannelInfo,
direction: Option<&'a ChannelUpdateInfo>,
direction: &'a ChannelUpdateInfo,
htlc_maximum_msat: u64,
effective_capacity: EffectiveCapacity,
}

impl<'a> DirectedChannelInfo<'a> {
#[inline]
fn new(channel: &'a ChannelInfo, direction: Option<&'a ChannelUpdateInfo>) -> Self {
let htlc_maximum_msat = direction.map(|direction| direction.htlc_maximum_msat);
fn new(channel: &'a ChannelInfo, direction: &'a ChannelUpdateInfo) -> Self {
let mut htlc_maximum_msat = direction.htlc_maximum_msat;
let capacity_msat = channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);

let (htlc_maximum_msat, effective_capacity) = match (htlc_maximum_msat, capacity_msat) {
(Some(amount_msat), Some(capacity_msat)) => {
let htlc_maximum_msat = cmp::min(amount_msat, capacity_msat);
(htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) })
let effective_capacity = match capacity_msat {
Some(capacity_msat) => {
htlc_maximum_msat = cmp::min(htlc_maximum_msat, capacity_msat);
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: htlc_maximum_msat }
},
(Some(amount_msat), None) => {
(amount_msat, EffectiveCapacity::MaximumHTLC { amount_msat })
},
(None, Some(capacity_msat)) => {
(capacity_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: None })
},
(None, None) => (EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::Unknown),
None => EffectiveCapacity::MaximumHTLC { amount_msat: htlc_maximum_msat },
};

Self {
Expand All @@ -891,12 +885,11 @@ impl<'a> DirectedChannelInfo<'a> {
}

/// Returns information for the channel.
#[inline]
pub fn channel(&self) -> &'a ChannelInfo { self.channel }

/// Returns information for the direction.
pub fn direction(&self) -> Option<&'a ChannelUpdateInfo> { self.direction }

/// Returns the maximum HTLC amount allowed over the channel in the direction.
#[inline]
pub fn htlc_maximum_msat(&self) -> u64 {
self.htlc_maximum_msat
}
Expand All @@ -910,13 +903,9 @@ impl<'a> DirectedChannelInfo<'a> {
self.effective_capacity
}

/// Returns `Some` if [`ChannelUpdateInfo`] is available in the direction.
pub(super) fn with_update(self) -> Option<DirectedChannelInfoWithUpdate<'a>> {
match self.direction {
Some(_) => Some(DirectedChannelInfoWithUpdate { inner: self }),
None => None,
}
}
/// Returns information for the direction.
#[inline]
pub(super) fn direction(&self) -> &'a ChannelUpdateInfo { self.direction }
}

impl<'a> fmt::Debug for DirectedChannelInfo<'a> {
Expand All @@ -927,32 +916,6 @@ impl<'a> fmt::Debug for DirectedChannelInfo<'a> {
}
}

/// A [`DirectedChannelInfo`] with [`ChannelUpdateInfo`] available in its direction.
#[derive(Clone)]
pub(super) struct DirectedChannelInfoWithUpdate<'a> {
inner: DirectedChannelInfo<'a>,
}

impl<'a> DirectedChannelInfoWithUpdate<'a> {
/// Returns information for the channel.
#[inline]
pub(super) fn channel(&self) -> &'a ChannelInfo { &self.inner.channel }

/// Returns information for the direction.
#[inline]
pub(super) fn direction(&self) -> &'a ChannelUpdateInfo { self.inner.direction.unwrap() }

/// Returns the [`EffectiveCapacity`] of the channel in the direction.
#[inline]
pub(super) fn effective_capacity(&self) -> EffectiveCapacity { self.inner.effective_capacity() }
}

impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.inner.fmt(f)
}
}

/// The effective capacity of a channel for routing purposes.
///
/// While this may be smaller than the actual channel capacity, amounts greater than
Expand All @@ -976,7 +939,7 @@ pub enum EffectiveCapacity {
/// The funding amount denominated in millisatoshi.
capacity_msat: u64,
/// The maximum HTLC amount denominated in millisatoshi.
htlc_maximum_msat: Option<u64>
htlc_maximum_msat: u64
},
/// A capacity sufficient to route any payment, typically used for private channels provided by
/// an invoice.
Expand Down
45 changes: 18 additions & 27 deletions lightning/src/routing/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bitcoin::secp256k1::PublicKey;
use crate::ln::channelmanager::ChannelDetails;
use crate::ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
use crate::routing::gossip::{DirectedChannelInfoWithUpdate, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
use crate::routing::scoring::{ChannelUsage, Score};
use crate::util::ser::{Writeable, Readable, Writer};
use crate::util::logger::{Level, Logger};
Expand Down Expand Up @@ -421,7 +421,7 @@ enum CandidateRouteHop<'a> {
},
/// A hop found in the [`ReadOnlyNetworkGraph`], where the channel capacity may be unknown.
PublicHop {
info: DirectedChannelInfoWithUpdate<'a>,
info: DirectedChannelInfo<'a>,
short_channel_id: u64,
},
/// A hop to the payee found in the payment invoice, though not necessarily a direct channel.
Expand Down Expand Up @@ -494,10 +494,8 @@ fn max_htlc_from_capacity(capacity: EffectiveCapacity, max_channel_saturation_po
EffectiveCapacity::Unknown => EffectiveCapacity::Unknown.as_msat(),
EffectiveCapacity::MaximumHTLC { amount_msat } =>
amount_msat.checked_shr(saturation_shift).unwrap_or(0),
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: None } =>
capacity_msat.checked_shr(saturation_shift).unwrap_or(0),
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_max) } =>
cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_max),
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } =>
cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_maximum_msat),
}
}

Expand Down Expand Up @@ -1276,13 +1274,11 @@ where L::Target: Logger {
for chan_id in $node.channels.iter() {
let chan = network_channels.get(chan_id).unwrap();
if !chan.features.requires_unknown_bits() {
let (directed_channel, source) =
chan.as_directed_to(&$node_id).expect("inconsistent NetworkGraph");
if first_hops.is_none() || *source != our_node_id {
if let Some(direction) = directed_channel.direction() {
if direction.enabled {
if let Some((directed_channel, source)) = chan.as_directed_to(&$node_id) {
if first_hops.is_none() || *source != our_node_id {
if directed_channel.direction().enabled {
let candidate = CandidateRouteHop::PublicHop {
info: directed_channel.with_update().unwrap(),
info: directed_channel,
short_channel_id: *chan_id,
};
add_entry!(candidate, *source, $node_id,
Expand Down Expand Up @@ -1367,8 +1363,7 @@ where L::Target: Logger {
let candidate = network_channels
.get(&hop.short_channel_id)
.and_then(|channel| channel.as_directed_to(&target))
.and_then(|(channel, _)| channel.with_update())
.map(|info| CandidateRouteHop::PublicHop {
.map(|(info, _)| CandidateRouteHop::PublicHop {
info,
short_channel_id: hop.short_channel_id,
})
Expand Down Expand Up @@ -1816,10 +1811,8 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters,
random_channel.as_directed_from(&cur_node_id).map(|(dir_info, next_id)| {
if !nodes_to_avoid.iter().any(|x| x == next_id) {
nodes_to_avoid[random_hop] = *next_id;
dir_info.direction().map(|channel_update_info| {
random_hop_offset = channel_update_info.cltv_expiry_delta.into();
cur_hop = Some(*next_id);
});
random_hop_offset = dir_info.direction().cltv_expiry_delta.into();
cur_hop = Some(*next_id);
}
});
}
Expand Down Expand Up @@ -5214,14 +5207,12 @@ mod tests {
for channel_id in &cur_node.channels {
if let Some(channel_info) = network_channels.get(&channel_id) {
if let Some((dir_info, next_id)) = channel_info.as_directed_from(&cur_node_id) {
if let Some(channel_update_info) = dir_info.direction() {
let next_cltv_expiry_delta = channel_update_info.cltv_expiry_delta as u32;
if cur_path_cltv_deltas.iter().sum::<u32>()
.saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta {
let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone();
new_path_cltv_deltas.push(next_cltv_expiry_delta);
candidates.push_back((*next_id, new_path_cltv_deltas));
}
let next_cltv_expiry_delta = dir_info.direction().cltv_expiry_delta as u32;
if cur_path_cltv_deltas.iter().sum::<u32>()
.saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta {
let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone();
new_path_cltv_deltas.push(next_cltv_expiry_delta);
candidates.push_back((*next_id, new_path_cltv_deltas));
}
}
}
Expand Down Expand Up @@ -5398,7 +5389,7 @@ mod tests {
let usage = ChannelUsage {
amount_msat: 0,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: Some(1_000) },
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
};
scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[3]), 123);
scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[4]), 456);
Expand Down
Loading