Skip to content

Commit f3fd340

Browse files
committed
Use MockInstant for tests
1 parent b5d35c2 commit f3fd340

File tree

1 file changed

+65
-61
lines changed

1 file changed

+65
-61
lines changed

lightning/src/routing/gossip.rs

Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ use bitcoin::hashes::hex::ToHex;
4545

4646
#[cfg(feature = "std")]
4747
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;
4852

4953
/// We remove stale channel directional info two weeks after the last update, per BOLT 7's
5054
/// suggestion.
@@ -130,20 +134,18 @@ pub struct NetworkGraph<L: Deref> where L::Target: Logger {
130134
// Lock order: channels -> nodes
131135
channels: RwLock<BTreeMap<u64, ChannelInfo>>,
132136
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>>,
147149
}
148150

149151
/// A read-only view of [`NetworkGraph`].
@@ -1206,7 +1208,9 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
12061208
channels: RwLock::new(channels),
12071209
nodes: RwLock::new(nodes),
12081210
last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp),
1211+
#[cfg(feature = "std")]
12091212
removed_nodes: Mutex::new(HashMap::new()),
1213+
#[cfg(feature = "std")]
12101214
removed_channels: Mutex::new(HashMap::new()),
12111215
})
12121216
}
@@ -1244,7 +1248,9 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
12441248
channels: RwLock::new(BTreeMap::new()),
12451249
nodes: RwLock::new(BTreeMap::new()),
12461250
last_rapid_gossip_sync_timestamp: Mutex::new(None),
1251+
#[cfg(feature = "std")]
12471252
removed_nodes: Mutex::new(HashMap::new()),
1253+
#[cfg(feature = "std")]
12481254
removed_channels: Mutex::new(HashMap::new()),
12491255
}
12501256
}
@@ -1301,6 +1307,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
13011307
}
13021308

13031309
fn update_node_from_announcement_intern(&self, msg: &msgs::UnsignedNodeAnnouncement, full_msg: Option<&msgs::NodeAnnouncement>) -> Result<(), LightningError> {
1310+
#[cfg(feature = "std")]
13041311
{
13051312
if self.removed_nodes.lock().unwrap().contains_key(&NodeId::from_pubkey(&msg.node_id)) {
13061313
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 {
14621469
return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError});
14631470
}
14641471

1472+
#[cfg(feature = "std")]
14651473
{
14661474
let channels = self.channels.read().unwrap();
14671475

@@ -1495,7 +1503,8 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
14951503
}
14961504
}
14971505

1498-
{
1506+
#[cfg(feature = "std")]
1507+
{
14991508
let removed_nodes = self.removed_nodes.lock().unwrap();
15001509
let removed_channels = self.removed_channels.lock().unwrap();
15011510
if removed_channels.contains_key(&msg.short_channel_id) ||
@@ -1586,7 +1595,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
15861595
let mut nodes = self.nodes.write().unwrap();
15871596
let mut removed_nodes = self.removed_nodes.lock().unwrap();
15881597
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();
15901599

15911600
if let Some(node) = nodes.remove(&node_id) {
15921601
for scid in node.channels.iter() {
@@ -1625,10 +1634,12 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
16251634
/// can be resynced from gossip in the future.
16261635
///
16271636
/// 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.
16291638
pub fn remove_stale_channels_and_tracking(&self) {
16301639
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);
16321643
}
16331644

16341645
/// 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 {
16401651
/// pruning occur for updates which are at least two weeks old, which we implement here.
16411652
///
16421653
/// 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) {
16491656
let mut channels = self.channels.write().unwrap();
16501657
// Time out if we haven't received an update in at least 14 days.
16511658
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 {
16771684
self.remove_channel_in_nodes(&mut nodes, &info, scid);
16781685
}
16791686
}
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-
}
16881687
}
16891688

16901689
/// 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 {
18611860
($node_id: expr) => {
18621861
if let BtreeEntry::Occupied(mut entry) = nodes.entry($node_id) {
18631862
#[cfg(feature = "std")]
1864-
let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
1863+
let time = Instant::now();
18651864
#[cfg(feature = "std")]
18661865
self.removed_channels.lock().unwrap().insert(short_channel_id, time);
18671866

@@ -2206,24 +2205,28 @@ mod tests {
22062205
Err(e) => assert_eq!(e.err, "Already have chain-validated channel")
22072206
};
22082207

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());
22122214

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+
}
22212223

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+
}
22272230
}
22282231

22292232
// Don't relay valid channels with excess data
@@ -2533,11 +2536,11 @@ mod tests {
25332536
assert!(gossip_sync.handle_channel_update(&valid_channel_update).is_ok());
25342537
assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_some());
25352538

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);
25372540
assert_eq!(network_graph.read_only().channels().len(), 1);
25382541
assert_eq!(network_graph.read_only().nodes().len(), 2);
25392542

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);
25412544
#[cfg(feature = "std")]
25422545
{
25432546
// In std mode, a further check is performed before fully removing the channel -
@@ -2551,7 +2554,7 @@ mod tests {
25512554
use std::time::{SystemTime, UNIX_EPOCH};
25522555
let announcement_time = SystemTime::now().duration_since(UNIX_EPOCH)
25532556
.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(
25552558
announcement_time + 1 + STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS);
25562559
}
25572560

@@ -2560,28 +2563,29 @@ mod tests {
25602563

25612564
#[cfg(feature = "std")]
25622565
{
2563-
use std::time::{SystemTime, UNIX_EPOCH};
2566+
use util::time::tests::MockInstant as Instant;
2567+
use std::time::Duration;
25642568

25652569
// Clear tracked nodes and channels for clean slate
25662570
network_graph.removed_nodes.lock().unwrap().clear();
25672571
network_graph.removed_channels.lock().unwrap().clear();
25682572

25692573
// 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();
25722575
network_graph.removed_nodes.lock().unwrap().insert(
25732576
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);
25762579

25772580
// 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();
25792583
assert_eq!(network_graph.removed_nodes.lock().unwrap().len(), 1);
25802584
assert_eq!(network_graph.removed_channels.lock().unwrap().len(), 1);
25812585

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();
25852589
assert!(network_graph.removed_nodes.lock().unwrap().is_empty());
25862590
assert!(network_graph.removed_channels.lock().unwrap().is_empty());
25872591
}

0 commit comments

Comments
 (0)