@@ -16,6 +16,9 @@ use lightning::io;
16
16
use crate :: error:: GraphSyncError ;
17
17
use crate :: RapidGossipSync ;
18
18
19
+ #[ cfg( all( feature = "std" , not( test) ) ) ]
20
+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
21
+
19
22
#[ cfg( not( feature = "std" ) ) ]
20
23
use alloc:: { vec:: Vec , borrow:: ToOwned } ;
21
24
@@ -29,10 +32,30 @@ const GOSSIP_PREFIX: [u8; 4] = [76, 68, 75, 1];
29
32
/// avoid malicious updates being able to trigger excessive memory allocation.
30
33
const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY : u32 = 50_000 ;
31
34
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
+
32
39
impl < NG : Deref < Target =NetworkGraph < L > > , L : Deref > RapidGossipSync < NG , L > where L :: Target : Logger {
33
40
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 > (
34
56
& self ,
35
57
mut read_cursor : & mut R ,
58
+ current_time_unix : Option < u64 >
36
59
) -> Result < u32 , GraphSyncError > {
37
60
let mut prefix = [ 0u8 ; 4 ] ;
38
61
read_cursor. read_exact ( & mut prefix) ?;
@@ -43,6 +66,13 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
43
66
44
67
let chain_hash: BlockHash = Readable :: read ( read_cursor) ?;
45
68
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
+
46
76
// backdate the applied timestamp by a week
47
77
let backdated_timestamp = latest_seen_timestamp. saturating_sub ( 24 * 3600 * 7 ) ;
48
78
@@ -215,6 +245,7 @@ mod tests {
215
245
use lightning:: util:: test_utils:: TestLogger ;
216
246
217
247
use crate :: error:: GraphSyncError ;
248
+ use crate :: processing:: STALE_RGS_UPDATE_AGE_LIMIT_SECS ;
218
249
use crate :: RapidGossipSync ;
219
250
220
251
#[ test]
@@ -526,6 +557,115 @@ mod tests {
526
557
assert ! ( after. contains( "783241506229452801" ) ) ;
527
558
}
528
559
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
+
529
669
#[ test]
530
670
pub fn update_fails_with_unknown_version ( ) {
531
671
let unknown_version_input = vec ! [
0 commit comments