@@ -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 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,8 +245,28 @@ 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
251
+ const VALID_RGS_BINARY : [ u8 ; 300 ] = [
252
+ 76 , 68 , 75 , 1 , 111 , 226 , 140 , 10 , 182 , 241 , 179 , 114 , 193 , 166 , 162 , 70 , 174 , 99 , 247 ,
253
+ 79 , 147 , 30 , 131 , 101 , 225 , 90 , 8 , 156 , 104 , 214 , 25 , 0 , 0 , 0 , 0 , 0 , 97 , 227 , 98 , 218 ,
254
+ 0 , 0 , 0 , 4 , 2 , 22 , 7 , 207 , 206 , 25 , 164 , 197 , 231 , 230 , 231 , 56 , 102 , 61 , 250 , 251 ,
255
+ 187 , 172 , 38 , 46 , 79 , 247 , 108 , 44 , 155 , 48 , 219 , 238 , 252 , 53 , 192 , 6 , 67 , 2 , 36 , 125 ,
256
+ 157 , 176 , 223 , 175 , 234 , 116 , 94 , 248 , 201 , 225 , 97 , 235 , 50 , 47 , 115 , 172 , 63 , 136 ,
257
+ 88 , 216 , 115 , 11 , 111 , 217 , 114 , 84 , 116 , 124 , 231 , 107 , 2 , 158 , 1 , 242 , 121 , 152 , 106 ,
258
+ 204 , 131 , 186 , 35 , 93 , 70 , 216 , 10 , 237 , 224 , 183 , 89 , 95 , 65 , 3 , 83 , 185 , 58 , 138 ,
259
+ 181 , 64 , 187 , 103 , 127 , 68 , 50 , 2 , 201 , 19 , 17 , 138 , 136 , 149 , 185 , 226 , 156 , 137 , 175 ,
260
+ 110 , 32 , 237 , 0 , 217 , 90 , 31 , 100 , 228 , 149 , 46 , 219 , 175 , 168 , 77 , 4 , 143 , 38 , 128 ,
261
+ 76 , 97 , 0 , 0 , 0 , 2 , 0 , 0 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 0 , 1 , 0 , 0 , 255 , 2 , 68 ,
262
+ 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 ,
263
+ 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 29 , 129 , 25 , 192 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 60 , 0 , 0 ,
264
+ 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 ,
265
+ 0 , 0 , 1 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 255 , 2 , 68 , 226 , 0 , 6 , 11 , 0 , 1 ,
266
+ 0 , 0 , 1 ,
267
+ ] ;
268
+ const VALID_BINARY_TIMESTAMP : u64 = 1642291930 ;
269
+
220
270
#[ test]
221
271
fn network_graph_fails_to_update_from_clipped_input ( ) {
222
272
let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
@@ -478,32 +528,14 @@ mod tests {
478
528
479
529
#[ test]
480
530
fn full_update_succeeds ( ) {
481
- let valid_input = vec ! [
482
- 76 , 68 , 75 , 1 , 111 , 226 , 140 , 10 , 182 , 241 , 179 , 114 , 193 , 166 , 162 , 70 , 174 , 99 , 247 ,
483
- 79 , 147 , 30 , 131 , 101 , 225 , 90 , 8 , 156 , 104 , 214 , 25 , 0 , 0 , 0 , 0 , 0 , 97 , 227 , 98 , 218 ,
484
- 0 , 0 , 0 , 4 , 2 , 22 , 7 , 207 , 206 , 25 , 164 , 197 , 231 , 230 , 231 , 56 , 102 , 61 , 250 , 251 ,
485
- 187 , 172 , 38 , 46 , 79 , 247 , 108 , 44 , 155 , 48 , 219 , 238 , 252 , 53 , 192 , 6 , 67 , 2 , 36 , 125 ,
486
- 157 , 176 , 223 , 175 , 234 , 116 , 94 , 248 , 201 , 225 , 97 , 235 , 50 , 47 , 115 , 172 , 63 , 136 ,
487
- 88 , 216 , 115 , 11 , 111 , 217 , 114 , 84 , 116 , 124 , 231 , 107 , 2 , 158 , 1 , 242 , 121 , 152 , 106 ,
488
- 204 , 131 , 186 , 35 , 93 , 70 , 216 , 10 , 237 , 224 , 183 , 89 , 95 , 65 , 3 , 83 , 185 , 58 , 138 ,
489
- 181 , 64 , 187 , 103 , 127 , 68 , 50 , 2 , 201 , 19 , 17 , 138 , 136 , 149 , 185 , 226 , 156 , 137 , 175 ,
490
- 110 , 32 , 237 , 0 , 217 , 90 , 31 , 100 , 228 , 149 , 46 , 219 , 175 , 168 , 77 , 4 , 143 , 38 , 128 ,
491
- 76 , 97 , 0 , 0 , 0 , 2 , 0 , 0 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 0 , 1 , 0 , 0 , 255 , 2 , 68 ,
492
- 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 ,
493
- 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 29 , 129 , 25 , 192 , 255 , 8 , 153 , 192 , 0 , 2 , 27 , 0 , 0 , 60 , 0 , 0 ,
494
- 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 ,
495
- 0 , 0 , 1 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 0 , 58 , 85 , 116 , 216 , 255 , 2 , 68 , 226 , 0 , 6 , 11 , 0 , 1 ,
496
- 0 , 0 , 1 ,
497
- ] ;
498
-
499
531
let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
500
532
let logger = TestLogger :: new ( ) ;
501
533
let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
502
534
503
535
assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
504
536
505
537
let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
506
- let update_result = rapid_sync. update_network_graph ( & valid_input [ .. ] ) ;
538
+ let update_result = rapid_sync. update_network_graph ( & VALID_RGS_BINARY ) ;
507
539
if update_result. is_err ( ) {
508
540
panic ! ( "Unexpected update result: {:?}" , update_result)
509
541
}
@@ -526,6 +558,58 @@ mod tests {
526
558
assert ! ( after. contains( "783241506229452801" ) ) ;
527
559
}
528
560
561
+ #[ test]
562
+ fn full_update_succeeds_at_the_beginning_of_the_unix_era ( ) {
563
+ let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
564
+ let logger = TestLogger :: new ( ) ;
565
+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
566
+
567
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
568
+
569
+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
570
+ // this is mostly for checking uint underflow issues before the fuzzer does
571
+ let update_result = rapid_sync. update_network_graph_no_std ( & VALID_RGS_BINARY , Some ( 0 ) ) ;
572
+ assert ! ( update_result. is_ok( ) ) ;
573
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 2 ) ;
574
+ }
575
+
576
+ #[ test]
577
+ fn timestamp_edge_cases_are_handled_correctly ( ) {
578
+ // this is the timestamp encoded in the binary data of valid_input below
579
+ let block_hash = genesis_block ( Network :: Bitcoin ) . block_hash ( ) ;
580
+ let logger = TestLogger :: new ( ) ;
581
+
582
+ let latest_succeeding_time = VALID_BINARY_TIMESTAMP + STALE_RGS_UPDATE_AGE_LIMIT_SECS ;
583
+ let earliest_failing_time = latest_succeeding_time + 1 ;
584
+
585
+ {
586
+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
587
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
588
+
589
+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
590
+ let update_result = rapid_sync. update_network_graph_no_std ( & VALID_RGS_BINARY , Some ( latest_succeeding_time) ) ;
591
+ assert ! ( update_result. is_ok( ) ) ;
592
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 2 ) ;
593
+ }
594
+
595
+ {
596
+ let network_graph = NetworkGraph :: new ( block_hash, & logger) ;
597
+ assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 0 ) ;
598
+
599
+ let rapid_sync = RapidGossipSync :: new ( & network_graph) ;
600
+ let update_result = rapid_sync. update_network_graph_no_std ( & VALID_RGS_BINARY , Some ( earliest_failing_time) ) ;
601
+ assert ! ( update_result. is_err( ) ) ;
602
+ if let Err ( GraphSyncError :: LightningError ( lightning_error) ) = update_result {
603
+ assert_eq ! (
604
+ lightning_error. err,
605
+ "Rapid Gossip Sync data is more than two weeks old"
606
+ ) ;
607
+ } else {
608
+ panic ! ( "Unexpected update result: {:?}" , update_result)
609
+ }
610
+ }
611
+ }
612
+
529
613
#[ test]
530
614
pub fn update_fails_with_unknown_version ( ) {
531
615
let unknown_version_input = vec ! [
0 commit comments