@@ -45,6 +45,10 @@ use bitcoin::hashes::hex::ToHex;
45
45
46
46
#[ cfg( feature = "std" ) ]
47
47
use std:: time:: { SystemTime , UNIX_EPOCH } ;
48
+ #[ cfg( all( not( test) , feature = "std" ) ) ]
49
+ use std:: time:: Instant ;
50
+ #[ cfg( all( test, feature = "std" ) ) ]
51
+ use util:: time:: tests:: MockInstant as Instant ;
48
52
49
53
/// We remove stale channel directional info two weeks after the last update, per BOLT 7's
50
54
/// suggestion.
@@ -130,20 +134,18 @@ pub struct NetworkGraph<L: Deref> where L::Target: Logger {
130
134
// Lock order: channels -> nodes
131
135
channels : RwLock < BTreeMap < u64 , ChannelInfo > > ,
132
136
nodes : RwLock < BTreeMap < NodeId , NodeInfo > > ,
133
- /// Keeps track of [`NodeId`]s for we have explicitly
134
- /// removed due to permanent failure so that we don't resync them
135
- /// from gossip. Each [`NodeId`] is mapped to the UNIX timestamp of when
136
- /// we removed it so that we can forget we removed it after some
137
- /// time (by removing it from this map) and it can be resynced from
138
- /// gossip if it appears again.
139
- removed_nodes : Mutex < HashMap < NodeId , u64 > > ,
140
- /// Keeps track of short channel IDs for channels we have explicitly
141
- /// removed due to permanent failure so that we don't resync them
142
- /// from gossip. Each ID is mapped to the UNIX timestamp of when
143
- /// we removed it so that we can forget we removed them after some
144
- /// time (by removing them from this map) and they can be resynced from
145
- /// gossip if they appear again.
146
- removed_channels : Mutex < HashMap < u64 , u64 > > ,
137
+ #[ cfg( feature = "std" ) ]
138
+ /// Keeps track of [`NodeId`]s we have explicitly removed due to permanent failure so that we
139
+ /// don't resync them from gossip. Each [`NodeId`] is mapped to the isntant when we removed it
140
+ /// from the network graph so that we can forget we removed it after some time (by removing it
141
+ /// from this map) and it can be resynced from gossip if it appears again.
142
+ removed_nodes : Mutex < HashMap < NodeId , Instant > > ,
143
+ #[ cfg( feature = "std" ) ]
144
+ /// Keeps track of short channel IDs for channels we have explicitly removed due to permanent
145
+ /// failure so that we don't resync them from gossip. Each SCID is mapped to the instant when we
146
+ /// removed it from the network graph so that we can forget we removed it after some time (by
147
+ /// removing it from this map) and it can be resynced from gossip if it appears again.
148
+ removed_channels : Mutex < HashMap < u64 , Instant > > ,
147
149
}
148
150
149
151
/// A read-only view of [`NetworkGraph`].
@@ -1206,7 +1208,9 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
1206
1208
channels : RwLock :: new ( channels) ,
1207
1209
nodes : RwLock :: new ( nodes) ,
1208
1210
last_rapid_gossip_sync_timestamp : Mutex :: new ( last_rapid_gossip_sync_timestamp) ,
1211
+ #[ cfg( feature = "std" ) ]
1209
1212
removed_nodes : Mutex :: new ( HashMap :: new ( ) ) ,
1213
+ #[ cfg( feature = "std" ) ]
1210
1214
removed_channels : Mutex :: new ( HashMap :: new ( ) ) ,
1211
1215
} )
1212
1216
}
@@ -1244,7 +1248,9 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1244
1248
channels : RwLock :: new ( BTreeMap :: new ( ) ) ,
1245
1249
nodes : RwLock :: new ( BTreeMap :: new ( ) ) ,
1246
1250
last_rapid_gossip_sync_timestamp : Mutex :: new ( None ) ,
1251
+ #[ cfg( feature = "std" ) ]
1247
1252
removed_nodes : Mutex :: new ( HashMap :: new ( ) ) ,
1253
+ #[ cfg( feature = "std" ) ]
1248
1254
removed_channels : Mutex :: new ( HashMap :: new ( ) ) ,
1249
1255
}
1250
1256
}
@@ -1301,6 +1307,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1301
1307
}
1302
1308
1303
1309
fn update_node_from_announcement_intern ( & self , msg : & msgs:: UnsignedNodeAnnouncement , full_msg : Option < & msgs:: NodeAnnouncement > ) -> Result < ( ) , LightningError > {
1310
+ #[ cfg( feature = "std" ) ]
1304
1311
{
1305
1312
if self . removed_nodes . lock ( ) . unwrap ( ) . contains_key ( & NodeId :: from_pubkey ( & msg. node_id ) ) {
1306
1313
return Err ( LightningError { err : "Node was removed from our network graph recently" . to_owned ( ) , action : ErrorAction :: IgnoreAndLog ( Level :: Gossip ) } ) ;
@@ -1462,6 +1469,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1462
1469
return Err ( LightningError { err : "Channel announcement node had a channel with itself" . to_owned ( ) , action : ErrorAction :: IgnoreError } ) ;
1463
1470
}
1464
1471
1472
+ #[ cfg( feature = "std" ) ]
1465
1473
{
1466
1474
let channels = self . channels . read ( ) . unwrap ( ) ;
1467
1475
@@ -1495,7 +1503,8 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1495
1503
}
1496
1504
}
1497
1505
1498
- {
1506
+ #[ cfg( feature = "std" ) ]
1507
+ {
1499
1508
let removed_nodes = self . removed_nodes . lock ( ) . unwrap ( ) ;
1500
1509
let removed_channels = self . removed_channels . lock ( ) . unwrap ( ) ;
1501
1510
if removed_channels. contains_key ( & msg. short_channel_id ) ||
@@ -1586,7 +1595,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1586
1595
let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1587
1596
let mut removed_nodes = self . removed_nodes . lock ( ) . unwrap ( ) ;
1588
1597
let mut removed_channels = self . removed_channels . lock ( ) . unwrap ( ) ;
1589
- let time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
1598
+ let time = Instant :: now ( ) ;
1590
1599
1591
1600
if let Some ( node) = nodes. remove ( & node_id) {
1592
1601
for scid in node. channels . iter ( ) {
@@ -1625,10 +1634,12 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1625
1634
/// can be resynced from gossip in the future.
1626
1635
///
1627
1636
/// This method is only available with the `std` feature. See
1628
- /// [`NetworkGraph::remove_stale_channels_and_tracking_with_time `] for `no-std` use.
1637
+ /// [`NetworkGraph::remove_stale_channels_with_time `] for `no-std` use.
1629
1638
pub fn remove_stale_channels_and_tracking ( & self ) {
1630
1639
let time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
1631
- self . remove_stale_channels_and_tracking_with_time ( time) ;
1640
+ self . remove_stale_channels_with_time ( time) ;
1641
+ self . removed_nodes . lock ( ) . unwrap ( ) . retain ( |_, time| time. elapsed ( ) . as_secs ( ) < STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1642
+ self . removed_channels . lock ( ) . unwrap ( ) . retain ( |_, time| time. elapsed ( ) . as_secs ( ) < STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1632
1643
}
1633
1644
1634
1645
/// Removes information about channels that we haven't heard any updates about in some time.
@@ -1640,12 +1651,8 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1640
1651
/// pruning occur for updates which are at least two weeks old, which we implement here.
1641
1652
///
1642
1653
/// This function takes the current unix time as an argument. For users with the `std` feature
1643
- /// enabled, [`NetworkGraph::remove_stale_channels`] may be preferable.
1644
- ///
1645
- /// When the `std` feature is enabled then this method will also remove entries from
1646
- /// [`NetworkGraph::removed_nodes`] and [`NetworkGraph::removed_channels`] if they have been in
1647
- /// the map for a while so that these can be resynced from gossip in the future.
1648
- pub fn remove_stale_channels_and_tracking_with_time ( & self , current_time_unix : u64 ) {
1654
+ /// enabled, [`NetworkGraph::remove_stale_channels_and_tracking`] may be preferable.
1655
+ pub fn remove_stale_channels_with_time ( & self , current_time_unix : u64 ) {
1649
1656
let mut channels = self . channels . write ( ) . unwrap ( ) ;
1650
1657
// Time out if we haven't received an update in at least 14 days.
1651
1658
if current_time_unix > u32:: max_value ( ) as u64 { return ; } // Remove by 2106
@@ -1677,14 +1684,6 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1677
1684
self . remove_channel_in_nodes ( & mut nodes, & info, scid) ;
1678
1685
}
1679
1686
}
1680
-
1681
- // We only bother to remove nodes and channels from tracking in std as they're only ever
1682
- // added to tracking with std.
1683
- #[ cfg( feature = "std" ) ]
1684
- {
1685
- self . removed_nodes . lock ( ) . unwrap ( ) . retain ( |_, timestamp| current_time_unix. saturating_sub ( * timestamp) < STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1686
- self . removed_channels . lock ( ) . unwrap ( ) . retain ( |_, timestamp| current_time_unix. saturating_sub ( * timestamp) < STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
1687
- }
1688
1687
}
1689
1688
1690
1689
/// For an already known (from announcement) channel, update info about one of the directions
@@ -1861,7 +1860,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1861
1860
( $node_id: expr) => {
1862
1861
if let BtreeEntry :: Occupied ( mut entry) = nodes. entry( $node_id) {
1863
1862
#[ cfg( feature = "std" ) ]
1864
- let time = SystemTime :: now( ) . duration_since ( UNIX_EPOCH ) . expect ( "Time must be > 1970" ) . as_secs ( ) ;
1863
+ let time = Instant :: now( ) ;
1865
1864
#[ cfg( feature = "std" ) ]
1866
1865
self . removed_channels. lock( ) . unwrap( ) . insert( short_channel_id, time) ;
1867
1866
@@ -2206,24 +2205,28 @@ mod tests {
2206
2205
Err ( e) => assert_eq ! ( e. err, "Already have chain-validated channel" )
2207
2206
} ;
2208
2207
2209
- // Insert node 1 into removed_nodes map to track it as removed.
2210
- gossip_sync. network_graph ( ) . removed_nodes . lock ( ) . unwrap ( ) . insert ( NodeId :: from_pubkey (
2211
- & PublicKey :: from_secret_key ( & secp_ctx, node_1_privkey) ) , 0 ) ;
2208
+ #[ cfg( feature = "std" ) ]
2209
+ {
2210
+ use util:: time:: tests:: MockInstant as Instant ;
2211
+ // Insert node 1 into removed_nodes map to track it as removed.
2212
+ gossip_sync. network_graph ( ) . removed_nodes . lock ( ) . unwrap ( ) . insert ( NodeId :: from_pubkey (
2213
+ & PublicKey :: from_secret_key ( & secp_ctx, node_1_privkey) ) , Instant :: now ( ) ) ;
2212
2214
2213
- // Return error and ignore valid channel announcement if one of the nodes has been tracked as removed.
2214
- let valid_announcement = get_signed_channel_announcement ( |unsigned_announcement| {
2215
- unsigned_announcement. short_channel_id += 3 ;
2216
- } , node_1_privkey, node_2_privkey, & secp_ctx) ;
2217
- match gossip_sync. handle_channel_announcement ( & valid_announcement) {
2218
- Ok ( _) => panic ! ( ) ,
2219
- Err ( e) => assert_eq ! ( e. err, "Channel or one of its nodes was removed from our network graph recently" )
2220
- }
2215
+ // Return error and ignore valid channel announcement if one of the nodes has been tracked as removed.
2216
+ let valid_announcement = get_signed_channel_announcement ( |unsigned_announcement| {
2217
+ unsigned_announcement. short_channel_id += 3 ;
2218
+ } , node_1_privkey, node_2_privkey, & secp_ctx) ;
2219
+ match gossip_sync. handle_channel_announcement ( & valid_announcement) {
2220
+ Ok ( _) => panic ! ( ) ,
2221
+ Err ( e) => assert_eq ! ( e. err, "Channel or one of its nodes was removed from our network graph recently" )
2222
+ }
2221
2223
2222
- // But handle above channel announcement if the node is not being tracked as removed anymore.
2223
- gossip_sync. network_graph . removed_nodes . lock ( ) . unwrap ( ) . clear ( ) ;
2224
- match gossip_sync. handle_channel_announcement ( & valid_announcement) {
2225
- Ok ( res) => assert ! ( res) ,
2226
- _ => panic ! ( )
2224
+ // But handle above channel announcement if the node is not being tracked as removed anymore.
2225
+ gossip_sync. network_graph . removed_nodes . lock ( ) . unwrap ( ) . clear ( ) ;
2226
+ match gossip_sync. handle_channel_announcement ( & valid_announcement) {
2227
+ Ok ( res) => assert ! ( res) ,
2228
+ _ => panic ! ( )
2229
+ }
2227
2230
}
2228
2231
2229
2232
// Don't relay valid channels with excess data
@@ -2533,11 +2536,11 @@ mod tests {
2533
2536
assert ! ( gossip_sync. handle_channel_update( & valid_channel_update) . is_ok( ) ) ;
2534
2537
assert ! ( network_graph. read_only( ) . channels( ) . get( & short_channel_id) . unwrap( ) . one_to_two. is_some( ) ) ;
2535
2538
2536
- network_graph. remove_stale_channels_and_tracking_with_time ( 100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2539
+ network_graph. remove_stale_channels_with_time ( 100 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2537
2540
assert_eq ! ( network_graph. read_only( ) . channels( ) . len( ) , 1 ) ;
2538
2541
assert_eq ! ( network_graph. read_only( ) . nodes( ) . len( ) , 2 ) ;
2539
2542
2540
- network_graph. remove_stale_channels_and_tracking_with_time ( 101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2543
+ network_graph. remove_stale_channels_with_time ( 101 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2541
2544
#[ cfg( feature = "std" ) ]
2542
2545
{
2543
2546
// In std mode, a further check is performed before fully removing the channel -
@@ -2551,7 +2554,7 @@ mod tests {
2551
2554
use std:: time:: { SystemTime , UNIX_EPOCH } ;
2552
2555
let announcement_time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH )
2553
2556
. expect ( "Time must be > 1970" ) . as_secs ( ) ;
2554
- network_graph. remove_stale_channels_and_tracking_with_time (
2557
+ network_graph. remove_stale_channels_with_time (
2555
2558
announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2556
2559
}
2557
2560
@@ -2560,28 +2563,29 @@ mod tests {
2560
2563
2561
2564
#[ cfg( feature = "std" ) ]
2562
2565
{
2563
- use std:: time:: { SystemTime , UNIX_EPOCH } ;
2566
+ use util:: time:: tests:: MockInstant as Instant ;
2567
+ use std:: time:: Duration ;
2564
2568
2565
2569
// Clear tracked nodes and channels for clean slate
2566
2570
network_graph. removed_nodes . lock ( ) . unwrap ( ) . clear ( ) ;
2567
2571
network_graph. removed_channels . lock ( ) . unwrap ( ) . clear ( ) ;
2568
2572
2569
2573
// Track some nodes and channels as removed
2570
- let started_tracking_time = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH )
2571
- . expect ( "Time must be > 1970" ) . as_secs ( ) ;
2574
+ let started_tracking = Instant :: now ( ) ;
2572
2575
network_graph. removed_nodes . lock ( ) . unwrap ( ) . insert (
2573
2576
NodeId :: from_pubkey ( & PublicKey :: from_secret_key ( & secp_ctx, node_1_privkey) ) ,
2574
- started_tracking_time ) ;
2575
- network_graph. removed_channels . lock ( ) . unwrap ( ) . insert ( 1 , started_tracking_time ) ;
2577
+ started_tracking ) ;
2578
+ network_graph. removed_channels . lock ( ) . unwrap ( ) . insert ( 1 , started_tracking ) ;
2576
2579
2577
2580
// Should not remove from tracking if insufficient time has passed
2578
- network_graph. remove_stale_channels_and_tracking_with_time ( started_tracking_time + 1 ) ;
2581
+ Instant :: advance ( Duration :: from_secs ( STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS - 1 ) ) ;
2582
+ network_graph. remove_stale_channels_and_tracking ( ) ;
2579
2583
assert_eq ! ( network_graph. removed_nodes. lock( ) . unwrap( ) . len( ) , 1 ) ;
2580
2584
assert_eq ! ( network_graph. removed_channels. lock( ) . unwrap( ) . len( ) , 1 ) ;
2581
2585
2582
- // Node and channel entry should be removed on next call
2583
- network_graph . remove_stale_channels_and_tracking_with_time (
2584
- started_tracking_time + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS ) ;
2586
+ // Advance mock time so the entries are removed on next call
2587
+ Instant :: advance ( Duration :: from_secs ( 1 ) ) ;
2588
+ network_graph . remove_stale_channels_and_tracking ( ) ;
2585
2589
assert ! ( network_graph. removed_nodes. lock( ) . unwrap( ) . is_empty( ) ) ;
2586
2590
assert ! ( network_graph. removed_channels. lock( ) . unwrap( ) . is_empty( ) ) ;
2587
2591
}
0 commit comments