Skip to content

Commit f98cc06

Browse files
committed
Track lowest inbound channel fees per channel direction
This allows to avoid iterating through the nodes data to see what would be the cost to reach a given node while routing.
1 parent 15a5966 commit f98cc06

File tree

2 files changed

+74
-18
lines changed

2 files changed

+74
-18
lines changed

lightning/src/routing/gossip.rs

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -707,37 +707,45 @@ pub struct ChannelInfo {
707707
/// (which we can probably assume we are - no-std environments probably won't have a full
708708
/// network graph in memory!).
709709
announcement_received_time: u64,
710+
/// Lowest fees to enter the first direction, based on the cheapest channel to the source node.
711+
/// The two fields (flat and proportional fee) are independent,
712+
/// meaning they don't have to refer to the same channel.
713+
pub lowest_inbound_channel_fees_to_one: Option<RoutingFees>,
714+
/// Lowest fees to enter the second direction, based on the cheapest channel to the source node.
715+
/// The two fields (flat and proportional fee) are independent,
716+
/// meaning they don't have to refer to the same channel.
717+
pub lowest_inbound_channel_fees_to_two: Option<RoutingFees>,
710718
}
711719

712720
impl ChannelInfo {
713721
/// Returns a [`DirectedChannelInfo`] for the channel directed to the given `target` from a
714722
/// returned `source`, or `None` if `target` is not one of the channel's counterparties.
715723
pub fn as_directed_to(&self, target: &NodeId) -> Option<(DirectedChannelInfo, &NodeId)> {
716-
let (direction, source) = {
724+
let (direction, source, lowest_inbound_channel_fees) = {
717725
if target == &self.node_one {
718-
(self.two_to_one.as_ref(), &self.node_two)
726+
(self.two_to_one.as_ref(), &self.node_two, self.lowest_inbound_channel_fees_to_two)
719727
} else if target == &self.node_two {
720-
(self.one_to_two.as_ref(), &self.node_one)
728+
(self.one_to_two.as_ref(), &self.node_one, self.lowest_inbound_channel_fees_to_one)
721729
} else {
722730
return None;
723731
}
724732
};
725-
Some((DirectedChannelInfo::new(self, direction), source))
733+
Some((DirectedChannelInfo::new(self, direction, lowest_inbound_channel_fees), source))
726734
}
727735

728736
/// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
729737
/// returned `target`, or `None` if `source` is not one of the channel's counterparties.
730738
pub fn as_directed_from(&self, source: &NodeId) -> Option<(DirectedChannelInfo, &NodeId)> {
731-
let (direction, target) = {
739+
let (direction, target, lowest_inbound_channel_fees) = {
732740
if source == &self.node_one {
733-
(self.one_to_two.as_ref(), &self.node_two)
741+
(self.one_to_two.as_ref(), &self.node_two, self.lowest_inbound_channel_fees_to_two)
734742
} else if source == &self.node_two {
735-
(self.two_to_one.as_ref(), &self.node_one)
743+
(self.two_to_one.as_ref(), &self.node_one, self.lowest_inbound_channel_fees_to_one)
736744
} else {
737745
return None;
738746
}
739747
};
740-
Some((DirectedChannelInfo::new(self, direction), target))
748+
Some((DirectedChannelInfo::new(self, direction, lowest_inbound_channel_fees), target))
741749
}
742750

743751
/// Returns a [`ChannelUpdateInfo`] based on the direction implied by the channel_flag.
@@ -770,6 +778,8 @@ impl Writeable for ChannelInfo {
770778
(8, self.two_to_one, required),
771779
(10, self.capacity_sats, required),
772780
(12, self.announcement_message, required),
781+
(14, self.lowest_inbound_channel_fees_to_one, option),
782+
(16, self.lowest_inbound_channel_fees_to_two, option),
773783
});
774784
Ok(())
775785
}
@@ -803,6 +813,8 @@ impl Readable for ChannelInfo {
803813
let mut two_to_one_wrap: Option<ChannelUpdateInfoDeserWrapper> = None;
804814
init_tlv_field_var!(capacity_sats, required);
805815
init_tlv_field_var!(announcement_message, required);
816+
init_tlv_field_var!(lowest_inbound_channel_fees_to_one, option);
817+
init_tlv_field_var!(lowest_inbound_channel_fees_to_two, option);
806818
read_tlv_fields!(reader, {
807819
(0, features, required),
808820
(1, announcement_received_time, (default_value, 0)),
@@ -812,6 +824,8 @@ impl Readable for ChannelInfo {
812824
(8, two_to_one_wrap, ignorable),
813825
(10, capacity_sats, required),
814826
(12, announcement_message, required),
827+
(14, lowest_inbound_channel_fees_to_one, option),
828+
(16, lowest_inbound_channel_fees_to_two, option),
815829
});
816830

817831
Ok(ChannelInfo {
@@ -823,6 +837,8 @@ impl Readable for ChannelInfo {
823837
capacity_sats: init_tlv_based_struct_field!(capacity_sats, required),
824838
announcement_message: init_tlv_based_struct_field!(announcement_message, required),
825839
announcement_received_time: init_tlv_based_struct_field!(announcement_received_time, (default_value, 0)),
840+
lowest_inbound_channel_fees_to_one: init_tlv_based_struct_field!(lowest_inbound_channel_fees_to_one, option),
841+
lowest_inbound_channel_fees_to_two: init_tlv_based_struct_field!(lowest_inbound_channel_fees_to_two, option),
826842
})
827843
}
828844
}
@@ -835,11 +851,12 @@ pub struct DirectedChannelInfo<'a> {
835851
direction: Option<&'a ChannelUpdateInfo>,
836852
htlc_maximum_msat: u64,
837853
effective_capacity: EffectiveCapacity,
854+
lowest_inbound_channel_fees: Option<RoutingFees>,
838855
}
839856

840857
impl<'a> DirectedChannelInfo<'a> {
841858
#[inline]
842-
fn new(channel: &'a ChannelInfo, direction: Option<&'a ChannelUpdateInfo>) -> Self {
859+
fn new(channel: &'a ChannelInfo, direction: Option<&'a ChannelUpdateInfo>, lowest_inbound_channel_fees: Option<RoutingFees>) -> Self {
843860
let htlc_maximum_msat = direction.map(|direction| direction.htlc_maximum_msat);
844861
let capacity_msat = channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
845862

@@ -858,7 +875,7 @@ impl<'a> DirectedChannelInfo<'a> {
858875
};
859876

860877
Self {
861-
channel, direction, htlc_maximum_msat, effective_capacity
878+
channel, direction, htlc_maximum_msat, effective_capacity, lowest_inbound_channel_fees,
862879
}
863880
}
864881

@@ -882,6 +899,13 @@ impl<'a> DirectedChannelInfo<'a> {
882899
self.effective_capacity
883900
}
884901

902+
/// Returns the [`Option<RoutingFees>`] to reach the channel in the direction.
903+
///
904+
/// This is based on the known and enabled channels to the entry node.
905+
pub fn lowest_inbound_channel_fees(&self) -> Option<RoutingFees> {
906+
self.lowest_inbound_channel_fees
907+
}
908+
885909
/// Returns `Some` if [`ChannelUpdateInfo`] is available in the direction.
886910
pub(super) fn with_update(self) -> Option<DirectedChannelInfoWithUpdate<'a>> {
887911
match self.direction {
@@ -917,6 +941,10 @@ impl<'a> DirectedChannelInfoWithUpdate<'a> {
917941
/// Returns the [`EffectiveCapacity`] of the channel in the direction.
918942
#[inline]
919943
pub(super) fn effective_capacity(&self) -> EffectiveCapacity { self.inner.effective_capacity() }
944+
945+
#[inline]
946+
pub(super) fn lowest_inbound_channel_fees(&self) -> Option<RoutingFees> { self.inner.lowest_inbound_channel_fees() }
947+
920948
}
921949

922950
impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
@@ -1382,6 +1410,8 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
13821410
capacity_sats: None,
13831411
announcement_message: None,
13841412
announcement_received_time: timestamp,
1413+
lowest_inbound_channel_fees_to_one: None,
1414+
lowest_inbound_channel_fees_to_two: None,
13851415
};
13861416

13871417
self.add_channel_between_nodes(short_channel_id, channel_info, None)
@@ -1524,6 +1554,8 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
15241554
announcement_message: if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY
15251555
{ full_msg.cloned() } else { None },
15261556
announcement_received_time,
1557+
lowest_inbound_channel_fees_to_one: None,
1558+
lowest_inbound_channel_fees_to_two: None,
15271559
};
15281560

15291561
self.add_channel_between_nodes(msg.short_channel_id, chan_info, utxo_value)
@@ -1752,22 +1784,20 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17521784
}
17531785

17541786
let mut nodes = self.nodes.write().unwrap();
1787+
let node = nodes.get_mut(&dest_node_id).unwrap();
1788+
let mut updated_lowest_inbound_channel_fee = None;
17551789
if chan_enabled {
1756-
let node = nodes.get_mut(&dest_node_id).unwrap();
17571790
let mut base_msat = msg.fee_base_msat;
17581791
let mut proportional_millionths = msg.fee_proportional_millionths;
17591792
if let Some(fees) = node.lowest_inbound_channel_fees {
17601793
base_msat = cmp::min(base_msat, fees.base_msat);
17611794
proportional_millionths = cmp::min(proportional_millionths, fees.proportional_millionths);
17621795
}
1763-
node.lowest_inbound_channel_fees = Some(RoutingFees {
1796+
updated_lowest_inbound_channel_fee = Some(RoutingFees {
17641797
base_msat,
17651798
proportional_millionths
17661799
});
17671800
} else if chan_was_enabled {
1768-
let node = nodes.get_mut(&dest_node_id).unwrap();
1769-
let mut lowest_inbound_channel_fees = None;
1770-
17711801
for chan_id in node.channels.iter() {
17721802
let chan = channels.get(chan_id).unwrap();
17731803
let chan_info_opt;
@@ -1778,15 +1808,27 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17781808
}
17791809
if let Some(chan_info) = chan_info_opt {
17801810
if chan_info.enabled {
1781-
let fees = lowest_inbound_channel_fees.get_or_insert(RoutingFees {
1811+
let fees = updated_lowest_inbound_channel_fee.get_or_insert(RoutingFees {
17821812
base_msat: u32::max_value(), proportional_millionths: u32::max_value() });
17831813
fees.base_msat = cmp::min(fees.base_msat, chan_info.fees.base_msat);
17841814
fees.proportional_millionths = cmp::min(fees.proportional_millionths, chan_info.fees.proportional_millionths);
17851815
}
17861816
}
17871817
}
1818+
}
17881819

1789-
node.lowest_inbound_channel_fees = lowest_inbound_channel_fees;
1820+
if updated_lowest_inbound_channel_fee.is_some() {
1821+
node.lowest_inbound_channel_fees = updated_lowest_inbound_channel_fee;
1822+
1823+
for (_, chan) in channels.iter_mut() {
1824+
if chan.node_one == dest_node_id {
1825+
chan.lowest_inbound_channel_fees_to_two = updated_lowest_inbound_channel_fee;
1826+
}
1827+
1828+
if chan.node_two == dest_node_id {
1829+
chan.lowest_inbound_channel_fees_to_one = updated_lowest_inbound_channel_fee;
1830+
}
1831+
}
17901832
}
17911833

17921834
Ok(())
@@ -3019,6 +3061,8 @@ mod tests {
30193061
capacity_sats: None,
30203062
announcement_message: None,
30213063
announcement_received_time: 87654,
3064+
lowest_inbound_channel_fees_to_one: None,
3065+
lowest_inbound_channel_fees_to_two: None,
30223066
};
30233067

30243068
let mut encoded_chan_info: Vec<u8> = Vec::new();
@@ -3037,6 +3081,8 @@ mod tests {
30373081
capacity_sats: None,
30383082
announcement_message: None,
30393083
announcement_received_time: 87654,
3084+
lowest_inbound_channel_fees_to_one: None,
3085+
lowest_inbound_channel_fees_to_two: None,
30403086
};
30413087

30423088
let mut encoded_chan_info: Vec<u8> = Vec::new();

lightning/src/routing/router.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,16 @@ impl<'a> CandidateRouteHop<'a> {
483483
CandidateRouteHop::PrivateHop { .. } => EffectiveCapacity::Infinite,
484484
}
485485
}
486+
487+
fn lowest_inbound_channel_fees(&self) -> Option<RoutingFees> {
488+
match self {
489+
CandidateRouteHop::FirstHop { .. } => Some(RoutingFees {
490+
base_msat: 0, proportional_millionths: 0,
491+
}),
492+
CandidateRouteHop::PublicHop { info, .. } => info.lowest_inbound_channel_fees(),
493+
CandidateRouteHop::PrivateHop { .. } => None,
494+
}
495+
}
486496
}
487497

488498
#[inline]
@@ -1070,7 +1080,7 @@ where L::Target: Logger {
10701080
// as a way to reach the $dest_node_id.
10711081
let mut fee_base_msat = 0;
10721082
let mut fee_proportional_millionths = 0;
1073-
if let Some(Some(fees)) = network_nodes.get(&$src_node_id).map(|node| node.lowest_inbound_channel_fees) {
1083+
if let Some(fees) = $candidate.lowest_inbound_channel_fees() {
10741084
fee_base_msat = fees.base_msat;
10751085
fee_proportional_millionths = fees.proportional_millionths;
10761086
}

0 commit comments

Comments
 (0)