Merge pull request #2954 from TheBlueMatt/2024-03-test-ci-beta-fail
[rust-lightning] / lightning-rapid-gossip-sync / src / processing.rs
index 400fe1ccc5d4f803d395fbfa2adc2d066146957d..b3fae0ffd8bea8e19822c5a2cf9bc19d3fe33939 100644 (file)
@@ -2,7 +2,7 @@ use core::cmp::max;
 use core::ops::Deref;
 use core::sync::atomic::Ordering;
 
-use bitcoin::BlockHash;
+use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::PublicKey;
 
 use lightning::ln::msgs::{
@@ -14,13 +14,12 @@ use lightning::{log_debug, log_warn, log_trace, log_given_level, log_gossip};
 use lightning::util::ser::{BigSize, Readable};
 use lightning::io;
 
-use crate::error::GraphSyncError;
-use crate::RapidGossipSync;
+use crate::{GraphSyncError, RapidGossipSync};
 
 #[cfg(all(feature = "std", not(test)))]
 use std::time::{SystemTime, UNIX_EPOCH};
 
-#[cfg(not(feature = "std"))]
+#[cfg(all(not(feature = "std"), not(test)))]
 use alloc::{vec::Vec, borrow::ToOwned};
 
 /// The purpose of this prefix is to identify the serialization format, should other rapid gossip
@@ -38,13 +37,14 @@ const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
 const STALE_RGS_UPDATE_AGE_LIMIT_SECS: u64 = 60 * 60 * 24 * 14;
 
 impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
+       #[cfg(feature = "std")]
        pub(crate) fn update_network_graph_from_byte_stream<R: io::Read>(
                &self,
                read_cursor: &mut R,
        ) -> Result<u32, GraphSyncError> {
                #[allow(unused_mut, unused_assignments)]
                let mut current_time_unix = None;
-               #[cfg(all(feature = "std", not(test)))]
+               #[cfg(not(test))]
                {
                        // Note that many tests rely on being able to set arbitrarily old timestamps, thus we
                        // disable this check during tests!
@@ -66,7 +66,17 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                        return Err(DecodeError::UnknownVersion.into());
                }
 
-               let chain_hash: BlockHash = Readable::read(read_cursor)?;
+               let chain_hash: ChainHash = Readable::read(read_cursor)?;
+               let ng_chain_hash = self.network_graph.get_chain_hash();
+               if chain_hash != ng_chain_hash {
+                       return Err(
+                               LightningError {
+                                       err: "Rapid Gossip Sync data's chain hash does not match the network graph's".to_owned(),
+                                       action: ErrorAction::IgnoreError,
+                               }.into()
+                       );
+               }
+
                let latest_seen_timestamp: u32 = Readable::read(read_cursor)?;
 
                if let Some(time) = current_time_unix {
@@ -237,6 +247,11 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                }
 
                self.network_graph.set_last_rapid_gossip_sync_timestamp(latest_seen_timestamp);
+
+               if let Some(time) = current_time_unix {
+                       self.network_graph.remove_stale_channels_and_tracking_with_time(time)
+               }
+
                self.is_initial_sync_complete.store(true, Ordering::Release);
                log_trace!(self.logger, "Done processing RGS data from {}", latest_seen_timestamp);
                Ok(latest_seen_timestamp)
@@ -247,13 +262,14 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
 mod tests {
        use bitcoin::Network;
 
+       #[cfg(feature = "std")]
        use lightning::ln::msgs::DecodeError;
+
        use lightning::routing::gossip::NetworkGraph;
        use lightning::util::test_utils::TestLogger;
 
-       use crate::error::GraphSyncError;
        use crate::processing::STALE_RGS_UPDATE_AGE_LIMIT_SECS;
-       use crate::RapidGossipSync;
+       use crate::{GraphSyncError, RapidGossipSync};
 
        const VALID_RGS_BINARY: [u8; 300] = [
                76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -275,6 +291,7 @@ mod tests {
        const VALID_BINARY_TIMESTAMP: u64 = 1642291930;
 
        #[test]
+       #[cfg(feature = "std")]
        fn network_graph_fails_to_update_from_clipped_input() {
                let logger = TestLogger::new();
                let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
@@ -306,6 +323,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_ignores_missing_channel() {
                let incremental_update_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -326,6 +344,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_fails_without_prior_updates() {
                let announced_update_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -353,6 +372,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_only_update_fails_without_prior_same_direction_updates() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -408,6 +428,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn incremental_update_succeeds_with_prior_announcements_and_full_updates() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -467,6 +488,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn update_succeeds_when_duplicate_gossip_is_applied() {
                let initialization_input = vec![
                        76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -510,6 +532,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        fn full_update_succeeds() {
                let logger = TestLogger::new();
                let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
@@ -554,6 +577,34 @@ mod tests {
                assert_eq!(network_graph.read_only().channels().len(), 2);
        }
 
+       #[test]
+       fn prunes_after_update() {
+               // this is the timestamp encoded in the binary data of valid_input below
+               let logger = TestLogger::new();
+
+               let latest_nonpruning_time = VALID_BINARY_TIMESTAMP + 60 * 60 * 24 * 7;
+
+               {
+                       let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+
+                       let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time));
+                       assert!(update_result.is_ok());
+                       assert_eq!(network_graph.read_only().channels().len(), 2);
+               }
+
+               {
+                       let network_graph = NetworkGraph::new(Network::Bitcoin, &logger);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+
+                       let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time + 1));
+                       assert!(update_result.is_ok());
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
+               }
+       }
+
        #[test]
        fn timestamp_edge_cases_are_handled_correctly() {
                // this is the timestamp encoded in the binary data of valid_input below
@@ -569,7 +620,7 @@ mod tests {
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
                        let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_succeeding_time));
                        assert!(update_result.is_ok());
-                       assert_eq!(network_graph.read_only().channels().len(), 2);
+                       assert_eq!(network_graph.read_only().channels().len(), 0);
                }
 
                {
@@ -591,6 +642,7 @@ mod tests {
        }
 
        #[test]
+       #[cfg(feature = "std")]
        pub fn update_fails_with_unknown_version() {
                let unknown_version_input = vec![
                        76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
@@ -623,4 +675,22 @@ mod tests {
                        panic!("Unexpected update result: {:?}", update_result)
                }
        }
+
+       #[test]
+       fn fails_early_on_chain_hash_mismatch() {
+               let logger = TestLogger::new();
+               // Set to testnet so that the VALID_RGS_BINARY chain hash of mainnet does not match.
+               let network_graph = NetworkGraph::new(Network::Testnet, &logger);
+
+               assert_eq!(network_graph.read_only().channels().len(), 0);
+
+               let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
+               let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(0));
+               assert!(update_result.is_err());
+               if let Err(GraphSyncError::LightningError(err)) = update_result {
+                       assert_eq!(err.err, "Rapid Gossip Sync data's chain hash does not match the network graph's");
+               } else {
+                       panic!("Unexpected update result: {:?}", update_result)
+               }
+       }
 }