@@ -16,6 +16,9 @@ use lightning::io;
1616use crate :: error:: GraphSyncError ;
1717use crate :: RapidGossipSync ;
1818
19+ #[ cfg( all( feature = "std" , not( test) ) ) ]
20+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
21+
1922#[ cfg( not( feature = "std" ) ) ]
2023use alloc:: { vec:: Vec , borrow:: ToOwned } ;
2124
@@ -29,10 +32,30 @@ const GOSSIP_PREFIX: [u8; 4] = [76, 68, 75, 1];
2932/// avoid malicious updates being able to trigger excessive memory allocation.
3033const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY : u32 = 50_000 ;
3134
35+ /// We remove disallow gossip data that's more than two weeks old, per BOLT 7's
36+ /// suggestion.
37+ const STALE_RGS_UPDATE_AGE_LIMIT_SECS : u64 = 60 * 60 * 24 * 14 ;
38+
3239impl < NG : Deref < Target =NetworkGraph < L > > , L : Deref > RapidGossipSync < NG , L > where L :: Target : Logger {
3340 pub ( crate ) fn update_network_graph_from_byte_stream < R : io:: Read > (
41+ & self ,
42+ read_cursor : & mut R ,
43+ ) -> Result < u32 , GraphSyncError > {
44+ #[ allow( unused_mut) ]
45+ let mut current_time_unix = None ;
46+ #[ cfg( all( feature = "std" , not( test) ) ) ]
47+ {
48+ // Note that many tests rely on being able to set arbitrarily old timestamps, thus we
49+ // disable this check during tests!
50+ current_time_unix = Some ( SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ) ;
51+ }
52+ self . update_network_graph_from_byte_stream_no_std ( read_cursor, current_time_unix)
53+ }
54+
55+ pub ( crate ) fn update_network_graph_from_byte_stream_no_std < R : io:: Read > (
3456 & self ,
3557 mut read_cursor : & mut R ,
58+ current_time_unix : Option < u64 >
3659 ) -> Result < u32 , GraphSyncError > {
3760 let mut prefix = [ 0u8 ; 4 ] ;
3861 read_cursor. read_exact ( & mut prefix) ?;
@@ -43,6 +66,13 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
4366
4467 let chain_hash: BlockHash = Readable :: read ( read_cursor) ?;
4568 let latest_seen_timestamp: u32 = Readable :: read ( read_cursor) ?;
69+
70+ if let Some ( time) = current_time_unix {
71+ if ( latest_seen_timestamp as u64 ) < time. saturating_sub ( STALE_RGS_UPDATE_AGE_LIMIT_SECS ) {
72+ return Err ( LightningError { err : "Rapid Gossip Sync data is more than two weeks old" . to_owned ( ) , action : ErrorAction :: IgnoreError } . into ( ) ) ;
73+ }
74+ }
75+
4676 // backdate the applied timestamp by a week
4777 let backdated_timestamp = latest_seen_timestamp. saturating_sub ( 24 * 3600 * 7 ) ;
4878
@@ -215,6 +245,7 @@ mod tests {
215245 use lightning:: util:: test_utils:: TestLogger ;
216246
217247 use crate :: error:: GraphSyncError ;
248+ use crate :: processing:: STALE_RGS_UPDATE_AGE_LIMIT_SECS ;
218249 use crate :: RapidGossipSync ;
219250
220251 #[ test]
@@ -526,6 +557,115 @@ mod tests {
526557 assert ! ( after. contains( "783241506229452801" ) ) ;
527558 }
528559
560+ #[ test]
561+ fn full_update_succeeds_with_edge_timestamp_age ( ) {
562+ const LATEST_SEEN_TIMESTAMP : u64 = 1642291930 ;
563+ let valid_input = vec ! [
564+ 76 , 68 , 75 , 1 , 111 , 226 , 140 , 10 , 182 , 241 , 179 , 114 , 193 , 166 , 162 , 70 , 174 , 99 , 247 ,
565+ 79 , 147 , 30 , 131 , 101 , 225 , 90 , 8 , 156 , 104 , 214 , 25 , 0 , 0 , 0 , 0 , 0 , 97 , 227 , 98 , 218 ,
566+ 0 , 0 , 0 , 4 , 2 , 22 , 7 , 207 , 206 , 25 , 164 , 197 , 231 , 230 , 231 , 56 , 102 , 61 , 250 , 251 ,
567+ 187 , 172 , 38 , 46 , 79 , 247 , 108 , 44 , 155 , 48 , 219 , 238 , 252 , 53 , 192 , 6 , 67 , 2 , 36 , 125 ,
568+ 157 , 176 , 223 , 175 , 234 , 116 , 94 , 248 , 201 , 225 , 97 , 235 , 50 , 47 , 115 , 172 , 63 , 136 ,
569+ 88 , 216 , 115 , 11 , 111 , 217 , 114 , 84 , 116 , 124 , 231 , 107 , 2 , 158 , 1 , 242 , 121 , 152 , 106 ,
570+ 204 , 131 , 186 , 35 , 93 , 70 , 216 , 10 , 237 , 224 , 183 , 89 , 95 , 65 , 3 , 83 , 185 , 58 , 138 ,
571+ 181 , 64 , 187 , 103 , 127 , 68 , 50 , 2 , 201 , 19 , 17 , 138 , 136 , 149 , 185 , 226 , 156 , 137 , 175 ,
572+ 110 , 32 , 237 , 0 , 217 , 90 , 31 , 100 , 228 , 149 , 46 , 219 , 175 , 168 , 77 , 4 , 143 , 38 , 128 ,
573+ 76 , 97 , 0 , 0 , 0 , 2 , 0 , 0 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 0 , 1 , 0 , 0 , 255 , 2 , 68 ,
574+ 226 , 0 , 6 , 11 , 0 , 1 , 2 , 3 , 0 , 0 , 0 , 4 , 0 , 40 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 232 , 0 , 0 , 3 , 232 ,
575+ 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 29 , 129 , 25 , 192 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 60 , 0 , 0 ,
576+ 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 100 , 0 , 0 , 2 , 224 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 0 , 29 , 0 ,
577+ 0 , 0 , 1 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 255 , 2 , 68 , 226 , 0 , 6 , 11 , 0 , 1 ,
578+ 0 , 0 , 1 ,
579+ ] ;
580+
581+ let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
582+ let logger = TestLogger :: new ( ) ;
583+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
584+
585+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
586+
587+ let earliest_failing_time = LATEST_SEEN_TIMESTAMP + STALE_RGS_UPDATE_AGE_LIMIT_SECS ;
588+
589+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
590+ let update_result = rapid_sync. update_network_graph_no_std ( & valid_input[ ..] , Some ( earliest_failing_time) ) ;
591+ assert ! ( update_result. is_ok( ) ) ;
592+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 2 ) ;
593+ }
594+
595+ #[ test]
596+ fn full_update_succeeds_with_oldest_possible_timestamp ( ) {
597+ let valid_input = vec ! [
598+ 76 , 68 , 75 , 1 , 111 , 226 , 140 , 10 , 182 , 241 , 179 , 114 , 193 , 166 , 162 , 70 , 174 , 99 , 247 ,
599+ 79 , 147 , 30 , 131 , 101 , 225 , 90 , 8 , 156 , 104 , 214 , 25 , 0 , 0 , 0 , 0 , 0 , 97 , 227 , 98 , 218 ,
600+ 0 , 0 , 0 , 4 , 2 , 22 , 7 , 207 , 206 , 25 , 164 , 197 , 231 , 230 , 231 , 56 , 102 , 61 , 250 , 251 ,
601+ 187 , 172 , 38 , 46 , 79 , 247 , 108 , 44 , 155 , 48 , 219 , 238 , 252 , 53 , 192 , 6 , 67 , 2 , 36 , 125 ,
602+ 157 , 176 , 223 , 175 , 234 , 116 , 94 , 248 , 201 , 225 , 97 , 235 , 50 , 47 , 115 , 172 , 63 , 136 ,
603+ 88 , 216 , 115 , 11 , 111 , 217 , 114 , 84 , 116 , 124 , 231 , 107 , 2 , 158 , 1 , 242 , 121 , 152 , 106 ,
604+ 204 , 131 , 186 , 35 , 93 , 70 , 216 , 10 , 237 , 224 , 183 , 89 , 95 , 65 , 3 , 83 , 185 , 58 , 138 ,
605+ 181 , 64 , 187 , 103 , 127 , 68 , 50 , 2 , 201 , 19 , 17 , 138 , 136 , 149 , 185 , 226 , 156 , 137 , 175 ,
606+ 110 , 32 , 237 , 0 , 217 , 90 , 31 , 100 , 228 , 149 , 46 , 219 , 175 , 168 , 77 , 4 , 143 , 38 , 128 ,
607+ 76 , 97 , 0 , 0 , 0 , 2 , 0 , 0 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 0 , 1 , 0 , 0 , 255 , 2 , 68 ,
608+ 226 , 0 , 6 , 11 , 0 , 1 , 2 , 3 , 0 , 0 , 0 , 4 , 0 , 40 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 232 , 0 , 0 , 3 , 232 ,
609+ 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 29 , 129 , 25 , 192 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 60 , 0 , 0 ,
610+ 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 100 , 0 , 0 , 2 , 224 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 0 , 29 , 0 ,
611+ 0 , 0 , 1 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 255 , 2 , 68 , 226 , 0 , 6 , 11 , 0 , 1 ,
612+ 0 , 0 , 1 ,
613+ ] ;
614+
615+ let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
616+ let logger = TestLogger :: new ( ) ;
617+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
618+
619+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
620+
621+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
622+ let update_result = rapid_sync. update_network_graph_no_std ( & valid_input[ ..] , Some ( 0 ) ) ;
623+ assert ! ( update_result. is_ok( ) ) ;
624+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 2 ) ;
625+ }
626+
627+ #[ test]
628+ fn full_update_fails_with_old_timestamp ( ) {
629+ const LATEST_SEEN_TIMESTAMP : u64 = 1642291930 ;
630+ let valid_input = vec ! [
631+ 76 , 68 , 75 , 1 , 111 , 226 , 140 , 10 , 182 , 241 , 179 , 114 , 193 , 166 , 162 , 70 , 174 , 99 , 247 ,
632+ 79 , 147 , 30 , 131 , 101 , 225 , 90 , 8 , 156 , 104 , 214 , 25 , 0 , 0 , 0 , 0 , 0 , 97 , 227 , 98 , 218 ,
633+ 0 , 0 , 0 , 4 , 2 , 22 , 7 , 207 , 206 , 25 , 164 , 197 , 231 , 230 , 231 , 56 , 102 , 61 , 250 , 251 ,
634+ 187 , 172 , 38 , 46 , 79 , 247 , 108 , 44 , 155 , 48 , 219 , 238 , 252 , 53 , 192 , 6 , 67 , 2 , 36 , 125 ,
635+ 157 , 176 , 223 , 175 , 234 , 116 , 94 , 248 , 201 , 225 , 97 , 235 , 50 , 47 , 115 , 172 , 63 , 136 ,
636+ 88 , 216 , 115 , 11 , 111 , 217 , 114 , 84 , 116 , 124 , 231 , 107 , 2 , 158 , 1 , 242 , 121 , 152 , 106 ,
637+ 204 , 131 , 186 , 35 , 93 , 70 , 216 , 10 , 237 , 224 , 183 , 89 , 95 , 65 , 3 , 83 , 185 , 58 , 138 ,
638+ 181 , 64 , 187 , 103 , 127 , 68 , 50 , 2 , 201 , 19 , 17 , 138 , 136 , 149 , 185 , 226 , 156 , 137 , 175 ,
639+ 110 , 32 , 237 , 0 , 217 , 90 , 31 , 100 , 228 , 149 , 46 , 219 , 175 , 168 , 77 , 4 , 143 , 38 , 128 ,
640+ 76 , 97 , 0 , 0 , 0 , 2 , 0 , 0 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 0 , 1 , 0 , 0 , 255 , 2 , 68 ,
641+ 226 , 0 , 6 , 11 , 0 , 1 , 2 , 3 , 0 , 0 , 0 , 4 , 0 , 40 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 232 , 0 , 0 , 3 , 232 ,
642+ 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 29 , 129 , 25 , 192 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 60 , 0 , 0 ,
643+ 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 100 , 0 , 0 , 2 , 224 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 0 , 29 , 0 ,
644+ 0 , 0 , 1 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 255 , 2 , 68 , 226 , 0 , 6 , 11 , 0 , 1 ,
645+ 0 , 0 , 1 ,
646+ ] ;
647+
648+ let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
649+ let logger = TestLogger :: new ( ) ;
650+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
651+
652+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
653+
654+ let earliest_failing_time = LATEST_SEEN_TIMESTAMP + STALE_RGS_UPDATE_AGE_LIMIT_SECS + 1 ;
655+
656+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
657+ let update_result = rapid_sync. update_network_graph_no_std ( & valid_input[ ..] , Some ( earliest_failing_time) ) ;
658+ assert ! ( update_result. is_err( ) ) ;
659+ if let Err ( GraphSyncError :: LightningError ( lightning_error) ) = update_result {
660+ assert_eq ! (
661+ lightning_error. err,
662+ "Rapid Gossip Sync data is more than two weeks old"
663+ ) ;
664+ } else {
665+ panic ! ( "Unexpected update result: {:?}" , update_result)
666+ }
667+ }
668+
529669 #[ test]
530670 pub fn update_fails_with_unknown_version ( ) {
531671 let unknown_version_input = vec ! [
0 commit comments