Merge pull request #1843 from TheBlueMatt/2022-11-fix-bp-exit-docs
[rust-lightning] / lightning / src / routing / gossip.rs
index 14df033b69971c9db3240c71f409109dec94c9cc..00846a7ba794a1e3b9ba52319d1daf97641097b6 100644 (file)
@@ -31,6 +31,7 @@ use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, MaybeReadable}
 use crate::util::logger::{Logger, Level};
 use crate::util::events::{Event, EventHandler, MessageSendEvent, MessageSendEventsProvider};
 use crate::util::scid_utils::{block_from_scid, scid_from_parts, MAX_SCID_BLOCK};
+use crate::util::string::PrintableString;
 
 use crate::io;
 use crate::io_extras::{copy, sink};
@@ -1022,23 +1023,17 @@ pub struct NodeAlias(pub [u8; 32]);
 
 impl fmt::Display for NodeAlias {
        fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-               let control_symbol = core::char::REPLACEMENT_CHARACTER;
                let first_null = self.0.iter().position(|b| *b == 0).unwrap_or(self.0.len());
                let bytes = self.0.split_at(first_null).0;
                match core::str::from_utf8(bytes) {
-                       Ok(alias) => {
-                               for c in alias.chars() {
-                                       let mut bytes = [0u8; 4];
-                                       let c = if !c.is_control() { c } else { control_symbol };
-                                       f.write_str(c.encode_utf8(&mut bytes))?;
-                               }
-                       },
+                       Ok(alias) => PrintableString(alias).fmt(f)?,
                        Err(_) => {
+                               use core::fmt::Write;
                                for c in bytes.iter().map(|b| *b as char) {
                                        // Display printable ASCII characters
-                                       let mut bytes = [0u8; 4];
+                                       let control_symbol = core::char::REPLACEMENT_CHARACTER;
                                        let c = if c >= '\x20' && c <= '\x7e' { c } else { control_symbol };
-                                       f.write_str(c.encode_utf8(&mut bytes))?;
+                                       f.write_char(c)?;
                                }
                        },
                };
@@ -1653,7 +1648,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                        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.
@@ -1667,6 +1662,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                        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));
                        }
                }
 
@@ -2532,32 +2528,57 @@ mod tests {
                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")]
                {