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
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.
#[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 {
}
/// 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
}
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> {
}
}
-/// 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
/// 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.
if info.two_to_one.is_some() && info.two_to_one.as_ref().unwrap().last_update < min_time_unix {
info.two_to_one = None;
}
- if info.one_to_two.is_none() && info.two_to_one.is_none() {
+ if info.one_to_two.is_none() || info.two_to_one.is_none() {
// We check the announcement_received_time here to ensure we don't drop
// announcements that we just received and are just waiting for our peer to send a
// channel_update for.
for scid in scids_to_remove {
let info = channels.remove(&scid).expect("We just accessed this scid, it should be present");
Self::remove_channel_in_nodes(&mut nodes, &info, scid);
+ self.removed_channels.lock().unwrap().insert(scid, Some(current_time_unix));
}
}
assert!(network_graph.update_channel_from_announcement(&valid_channel_announcement, &chain_source).is_ok());
assert!(network_graph.read_only().channels().get(&short_channel_id).is_some());
+ // Submit two channel updates for each channel direction (update.flags bit).
let valid_channel_update = get_signed_channel_update(|_| {}, node_1_privkey, &secp_ctx);
assert!(gossip_sync.handle_channel_update(&valid_channel_update).is_ok());
assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_some());
+ let valid_channel_update_2 = get_signed_channel_update(|update| {update.flags |=1;}, node_2_privkey, &secp_ctx);
+ gossip_sync.handle_channel_update(&valid_channel_update_2).unwrap();
+ assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().two_to_one.is_some());
+
network_graph.remove_stale_channels_and_tracking_with_time(100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
assert_eq!(network_graph.read_only().channels().len(), 1);
assert_eq!(network_graph.read_only().nodes().len(), 2);
network_graph.remove_stale_channels_and_tracking_with_time(101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
+ #[cfg(not(feature = "std"))] {
+ // Make sure removed channels are tracked.
+ assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
+ }
+ network_graph.remove_stale_channels_and_tracking_with_time(101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS +
+ REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
+
#[cfg(feature = "std")]
{
// In std mode, a further check is performed before fully removing the channel -
// the channel_announcement must have been received at least two weeks ago. We
- // fudge that here by indicating the time has jumped two weeks. Note that the
- // directional channel information will have been removed already..
+ // fudge that here by indicating the time has jumped two weeks.
assert_eq!(network_graph.read_only().channels().len(), 1);
assert_eq!(network_graph.read_only().nodes().len(), 2);
- assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_none());
+ // Note that the directional channel information will have been removed already..
+ // We want to check that this will work even if *one* of the channel updates is recent,
+ // so we should add it with a recent timestamp.
+ assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_none());
use std::time::{SystemTime, UNIX_EPOCH};
let announcement_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
+ let valid_channel_update = get_signed_channel_update(|unsigned_channel_update| {
+ unsigned_channel_update.timestamp = (announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS) as u32;
+ }, node_1_privkey, &secp_ctx);
+ assert!(gossip_sync.handle_channel_update(&valid_channel_update).is_ok());
+ assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_some());
network_graph.remove_stale_channels_and_tracking_with_time(announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
+ // Make sure removed channels are tracked.
+ assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
+ // Provide a later time so that sufficient time has passed
+ network_graph.remove_stale_channels_and_tracking_with_time(announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS +
+ REMOVED_ENTRIES_TRACKING_AGE_LIMIT_SECS);
}
assert_eq!(network_graph.read_only().channels().len(), 0);
assert_eq!(network_graph.read_only().nodes().len(), 0);
+ assert!(network_graph.removed_channels.lock().unwrap().is_empty());
#[cfg(feature = "std")]
{