Skip to content

Commit 6d714b8

Browse files
committed
Track a counter for each node in our network graph
These counters are simply a unique number describing each node. They have no specific meaning, but start at 0 and count up, with counters being reused after a node has been deleted.
1 parent b8cdde8 commit 6d714b8

File tree

1 file changed

+67
-9
lines changed

1 file changed

+67
-9
lines changed

lightning/src/routing/gossip.rs

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ use crate::sync::Mutex;
4242
use crate::sync::{LockTestExt, RwLock, RwLockReadGuard};
4343
use core::ops::{Bound, Deref};
4444
use core::str::FromStr;
45-
#[cfg(feature = "std")]
4645
use core::sync::atomic::{AtomicUsize, Ordering};
4746
use core::{cmp, fmt};
4847

@@ -184,6 +183,8 @@ pub struct NetworkGraph<L: Deref> where L::Target: Logger {
184183
// Lock order: channels -> nodes
185184
channels: RwLock<IndexedMap<u64, ChannelInfo>>,
186185
nodes: RwLock<IndexedMap<NodeId, NodeInfo>>,
186+
removed_node_counters: Mutex<Vec<u32>>,
187+
next_node_counter: AtomicUsize,
187188
// Lock order: removed_channels -> removed_nodes
188189
//
189190
// NOTE: In the following `removed_*` maps, we use seconds since UNIX epoch to track time instead
@@ -1368,15 +1369,27 @@ impl Readable for NodeAlias {
13681369
}
13691370
}
13701371

1371-
#[derive(Clone, Debug, PartialEq, Eq)]
1372+
#[derive(Clone, Debug, Eq)]
13721373
/// Details about a node in the network, known from the network announcement.
13731374
pub struct NodeInfo {
13741375
/// All valid channels a node has announced
13751376
pub channels: Vec<u64>,
13761377
/// More information about a node from node_announcement.
13771378
/// Optional because we store a Node entry after learning about it from
13781379
/// a channel announcement, but before receiving a node announcement.
1379-
pub announcement_info: Option<NodeAnnouncementInfo>
1380+
pub announcement_info: Option<NodeAnnouncementInfo>,
1381+
/// In memory, each node is assigned a unique ID. They are eagerly reused, ensuring they remain
1382+
/// relatively dense.
1383+
///
1384+
/// These IDs allow the router to avoid a `HashMap` lookup by simply using this value as an
1385+
/// index in a `Vec`, skipping a big step in some of the hottest code when routing.
1386+
pub(crate) node_counter: u32,
1387+
}
1388+
1389+
impl PartialEq for NodeInfo {
1390+
fn eq(&self, o: &NodeInfo) -> bool {
1391+
self.channels == o.channels && self.announcement_info == o.announcement_info
1392+
}
13801393
}
13811394

13821395
impl NodeInfo {
@@ -1446,6 +1459,7 @@ impl Readable for NodeInfo {
14461459
Ok(NodeInfo {
14471460
announcement_info: announcement_info_wrap.map(|w| w.0),
14481461
channels,
1462+
node_counter: u32::max_value(),
14491463
})
14501464
}
14511465
}
@@ -1455,6 +1469,8 @@ const MIN_SERIALIZATION_VERSION: u8 = 1;
14551469

14561470
impl<L: Deref> Writeable for NetworkGraph<L> where L::Target: Logger {
14571471
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
1472+
self.test_node_counter_consistency();
1473+
14581474
write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
14591475

14601476
self.chain_hash.write(writer)?;
@@ -1493,11 +1509,15 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
14931509
channels.insert(chan_id, chan_info);
14941510
}
14951511
let nodes_count: u64 = Readable::read(reader)?;
1512+
// There shouldn't be anywhere near `u32::MAX` nodes, and we need some headroom to insert
1513+
// new nodes during sync, so reject any graphs claiming more than `u32::MAX / 2` nodes.
1514+
if nodes_count > u32::max_value() as u64 / 2 { return Err(DecodeError::InvalidValue); }
14961515
// In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
14971516
let mut nodes = IndexedMap::with_capacity(cmp::min(nodes_count as usize, 103500));
1498-
for _ in 0..nodes_count {
1517+
for i in 0..nodes_count {
14991518
let node_id = Readable::read(reader)?;
1500-
let node_info = Readable::read(reader)?;
1519+
let mut node_info: NodeInfo = Readable::read(reader)?;
1520+
node_info.node_counter = i as u32;
15011521
nodes.insert(node_id, node_info);
15021522
}
15031523

@@ -1512,6 +1532,8 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
15121532
logger,
15131533
channels: RwLock::new(channels),
15141534
nodes: RwLock::new(nodes),
1535+
removed_node_counters: Mutex::new(Vec::new()),
1536+
next_node_counter: AtomicUsize::new(nodes_count as usize),
15151537
last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp),
15161538
removed_nodes: Mutex::new(new_hash_map()),
15171539
removed_channels: Mutex::new(new_hash_map()),
@@ -1557,15 +1579,42 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
15571579
logger,
15581580
channels: RwLock::new(IndexedMap::new()),
15591581
nodes: RwLock::new(IndexedMap::new()),
1582+
next_node_counter: AtomicUsize::new(0),
1583+
removed_node_counters: Mutex::new(Vec::new()),
15601584
last_rapid_gossip_sync_timestamp: Mutex::new(None),
15611585
removed_channels: Mutex::new(new_hash_map()),
15621586
removed_nodes: Mutex::new(new_hash_map()),
15631587
pending_checks: utxo::PendingChecks::new(),
15641588
}
15651589
}
15661590

1591+
fn test_node_counter_consistency(&self) {
1592+
#[cfg(debug_assertions)] {
1593+
let nodes = self.nodes.read().unwrap();
1594+
let removed_node_counters = self.removed_node_counters.lock().unwrap();
1595+
let next_counter = self.next_node_counter.load(Ordering::Acquire);
1596+
assert!(next_counter < (u32::max_value() as usize) / 2);
1597+
let mut used_node_counters = vec![0u8; next_counter / 8 + 1];
1598+
1599+
for counter in removed_node_counters.iter() {
1600+
let pos = (*counter as usize) / 8;
1601+
let bit = 1 << (counter % 8);
1602+
assert_eq!(used_node_counters[pos] & bit, 0);
1603+
used_node_counters[pos] |= bit;
1604+
}
1605+
for (_, node) in nodes.unordered_iter() {
1606+
assert!((node.node_counter as usize) < next_counter);
1607+
let pos = (node.node_counter as usize) / 8;
1608+
let bit = 1 << (node.node_counter % 8);
1609+
assert_eq!(used_node_counters[pos] & bit, 0);
1610+
used_node_counters[pos] |= bit;
1611+
}
1612+
}
1613+
}
1614+
15671615
/// Returns a read-only view of the network graph.
15681616
pub fn read_only(&'_ self) -> ReadOnlyNetworkGraph<'_> {
1617+
self.test_node_counter_consistency();
15691618
let channels = self.channels.read().unwrap();
15701619
let nodes = self.nodes.read().unwrap();
15711620
ReadOnlyNetworkGraph {
@@ -1752,7 +1801,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17521801
// b) we don't track UTXOs of channels we know about and remove them if they
17531802
// get reorg'd out.
17541803
// c) it's unclear how to do so without exposing ourselves to massive DoS risk.
1755-
Self::remove_channel_in_nodes(&mut nodes, &entry.get(), short_channel_id);
1804+
self.remove_channel_in_nodes(&mut nodes, &entry.get(), short_channel_id);
17561805
*entry.get_mut() = channel_info;
17571806
} else {
17581807
return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreDuplicateGossip});
@@ -1769,9 +1818,13 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17691818
node_entry.into_mut().channels.push(short_channel_id);
17701819
},
17711820
IndexedMapEntry::Vacant(node_entry) => {
1821+
let mut removed_node_counters = self.removed_node_counters.lock().unwrap();
1822+
let node_counter = removed_node_counters.pop()
1823+
.unwrap_or(self.next_node_counter.fetch_add(1, Ordering::Relaxed) as u32);
17721824
node_entry.insert(NodeInfo {
17731825
channels: vec!(short_channel_id),
17741826
announcement_info: None,
1827+
node_counter,
17751828
});
17761829
}
17771830
};
@@ -1890,7 +1943,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
18901943
if let Some(chan) = channels.remove(&short_channel_id) {
18911944
let mut nodes = self.nodes.write().unwrap();
18921945
self.removed_channels.lock().unwrap().insert(short_channel_id, current_time_unix);
1893-
Self::remove_channel_in_nodes(&mut nodes, &chan, short_channel_id);
1946+
self.remove_channel_in_nodes(&mut nodes, &chan, short_channel_id);
18941947
}
18951948
}
18961949

@@ -1909,6 +1962,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
19091962
let mut removed_nodes = self.removed_nodes.lock().unwrap();
19101963

19111964
if let Some(node) = nodes.remove(&node_id) {
1965+
let mut removed_node_counters = self.removed_node_counters.lock().unwrap();
19121966
for scid in node.channels.iter() {
19131967
if let Some(chan_info) = channels.remove(scid) {
19141968
let other_node_id = if node_id == chan_info.node_one { chan_info.node_two } else { chan_info.node_one };
@@ -1917,12 +1971,14 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
19171971
*scid != *chan_id
19181972
});
19191973
if other_node_entry.get().channels.is_empty() {
1974+
removed_node_counters.push(other_node_entry.get().node_counter);
19201975
other_node_entry.remove_entry();
19211976
}
19221977
}
19231978
removed_channels.insert(*scid, current_time_unix);
19241979
}
19251980
}
1981+
removed_node_counters.push(node.node_counter);
19261982
removed_nodes.insert(node_id, current_time_unix);
19271983
}
19281984
}
@@ -1998,7 +2054,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
19982054
let mut nodes = self.nodes.write().unwrap();
19992055
for scid in scids_to_remove {
20002056
let info = channels.remove(&scid).expect("We just accessed this scid, it should be present");
2001-
Self::remove_channel_in_nodes(&mut nodes, &info, scid);
2057+
self.remove_channel_in_nodes(&mut nodes, &info, scid);
20022058
self.removed_channels.lock().unwrap().insert(scid, Some(current_time_unix));
20032059
}
20042060
}
@@ -2180,14 +2236,15 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
21802236
Ok(())
21812237
}
21822238

2183-
fn remove_channel_in_nodes(nodes: &mut IndexedMap<NodeId, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
2239+
fn remove_channel_in_nodes(&self, nodes: &mut IndexedMap<NodeId, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
21842240
macro_rules! remove_from_node {
21852241
($node_id: expr) => {
21862242
if let IndexedMapEntry::Occupied(mut entry) = nodes.entry($node_id) {
21872243
entry.get_mut().channels.retain(|chan_id| {
21882244
short_channel_id != *chan_id
21892245
});
21902246
if entry.get().channels.is_empty() {
2247+
self.removed_node_counters.lock().unwrap().push(entry.get().node_counter);
21912248
entry.remove_entry();
21922249
}
21932250
} else {
@@ -3604,6 +3661,7 @@ pub(crate) mod tests {
36043661
let valid_node_info = NodeInfo {
36053662
channels: Vec::new(),
36063663
announcement_info: Some(valid_node_ann_info),
3664+
node_counter: 0,
36073665
};
36083666

36093667
let mut encoded_valid_node_info = Vec::new();

0 commit comments

Comments
 (0)