Skip to content

Commit fdabe11

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 2701bc5 commit fdabe11

File tree

1 file changed

+65
-9
lines changed

1 file changed

+65
-9
lines changed

lightning/src/routing/gossip.rs

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use crate::io_extras::{copy, sink};
4040
use crate::prelude::*;
4141
use core::{cmp, fmt};
4242
use crate::sync::{RwLock, RwLockReadGuard, LockTestExt};
43-
#[cfg(feature = "std")]
4443
use core::sync::atomic::{AtomicUsize, Ordering};
4544
use crate::sync::Mutex;
4645
use core::ops::{Bound, Deref};
@@ -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
@@ -1333,15 +1334,27 @@ impl Readable for NodeAlias {
13331334
}
13341335
}
13351336

1336-
#[derive(Clone, Debug, PartialEq, Eq)]
1337+
#[derive(Clone, Debug, Eq)]
13371338
/// Details about a node in the network, known from the network announcement.
13381339
pub struct NodeInfo {
13391340
/// All valid channels a node has announced
13401341
pub channels: Vec<u64>,
13411342
/// More information about a node from node_announcement.
13421343
/// Optional because we store a Node entry after learning about it from
13431344
/// a channel announcement, but before receiving a node announcement.
1344-
pub announcement_info: Option<NodeAnnouncementInfo>
1345+
pub announcement_info: Option<NodeAnnouncementInfo>,
1346+
/// In memory, each node is assigned a unique ID. They are eagerly reused, ensuring they remain
1347+
/// relatively dense.
1348+
///
1349+
/// These IDs allow the router to avoid a `HashMap` lookup by simply using this value as an
1350+
/// index in a `Vec`, skipping a big step in some of the hottest code when routing.
1351+
pub(crate) node_counter: u32,
1352+
}
1353+
1354+
impl PartialEq for NodeInfo {
1355+
fn eq(&self, o: &NodeInfo) -> bool {
1356+
self.channels == o.channels && self.announcement_info == o.announcement_info
1357+
}
13451358
}
13461359

13471360
impl NodeInfo {
@@ -1411,6 +1424,7 @@ impl Readable for NodeInfo {
14111424
Ok(NodeInfo {
14121425
announcement_info: announcement_info_wrap.map(|w| w.0),
14131426
channels,
1427+
node_counter: u32::max_value(),
14141428
})
14151429
}
14161430
}
@@ -1420,6 +1434,8 @@ const MIN_SERIALIZATION_VERSION: u8 = 1;
14201434

14211435
impl<L: Deref> Writeable for NetworkGraph<L> where L::Target: Logger {
14221436
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
1437+
self.test_node_counter_consistency();
1438+
14231439
write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
14241440

14251441
self.chain_hash.write(writer)?;
@@ -1458,11 +1474,13 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
14581474
channels.insert(chan_id, chan_info);
14591475
}
14601476
let nodes_count: u64 = Readable::read(reader)?;
1477+
if nodes_count > u32::max_value() as u64 / 2 { return Err(DecodeError::InvalidValue); }
14611478
// In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
14621479
let mut nodes = IndexedMap::with_capacity(cmp::min(nodes_count as usize, 103500));
1463-
for _ in 0..nodes_count {
1480+
for i in 0..nodes_count {
14641481
let node_id = Readable::read(reader)?;
1465-
let node_info = Readable::read(reader)?;
1482+
let mut node_info: NodeInfo = Readable::read(reader)?;
1483+
node_info.node_counter = i as u32;
14661484
nodes.insert(node_id, node_info);
14671485
}
14681486

@@ -1477,6 +1495,8 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
14771495
logger,
14781496
channels: RwLock::new(channels),
14791497
nodes: RwLock::new(nodes),
1498+
removed_node_counters: Mutex::new(Vec::new()),
1499+
next_node_counter: AtomicUsize::new(nodes_count as usize),
14801500
last_rapid_gossip_sync_timestamp: Mutex::new(last_rapid_gossip_sync_timestamp),
14811501
removed_nodes: Mutex::new(new_hash_map()),
14821502
removed_channels: Mutex::new(new_hash_map()),
@@ -1522,15 +1542,42 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
15221542
logger,
15231543
channels: RwLock::new(IndexedMap::new()),
15241544
nodes: RwLock::new(IndexedMap::new()),
1545+
next_node_counter: AtomicUsize::new(0),
1546+
removed_node_counters: Mutex::new(Vec::new()),
15251547
last_rapid_gossip_sync_timestamp: Mutex::new(None),
15261548
removed_channels: Mutex::new(new_hash_map()),
15271549
removed_nodes: Mutex::new(new_hash_map()),
15281550
pending_checks: utxo::PendingChecks::new(),
15291551
}
15301552
}
15311553

1554+
fn test_node_counter_consistency(&self) {
1555+
#[cfg(debug_assertions)] {
1556+
let nodes = self.nodes.read().unwrap();
1557+
let removed_node_counters = self.removed_node_counters.lock().unwrap();
1558+
let next_counter = self.next_node_counter.load(Ordering::Acquire);
1559+
assert!(next_counter < (u32::max_value() as usize) / 2);
1560+
let mut used_node_counters = vec![0u8; next_counter / 8 + 1];
1561+
1562+
for counter in removed_node_counters.iter() {
1563+
let pos = (*counter as usize) / 8;
1564+
let bit = 1 << (counter % 8);
1565+
assert_eq!(used_node_counters[pos] & bit, 0);
1566+
used_node_counters[pos] |= bit;
1567+
}
1568+
for (_, node) in nodes.unordered_iter() {
1569+
assert!((node.node_counter as usize) < next_counter);
1570+
let pos = (node.node_counter as usize) / 8;
1571+
let bit = 1 << (node.node_counter % 8);
1572+
assert_eq!(used_node_counters[pos] & bit, 0);
1573+
used_node_counters[pos] |= bit;
1574+
}
1575+
}
1576+
}
1577+
15321578
/// Returns a read-only view of the network graph.
15331579
pub fn read_only(&'_ self) -> ReadOnlyNetworkGraph<'_> {
1580+
self.test_node_counter_consistency();
15341581
let channels = self.channels.read().unwrap();
15351582
let nodes = self.nodes.read().unwrap();
15361583
ReadOnlyNetworkGraph {
@@ -1717,7 +1764,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17171764
// b) we don't track UTXOs of channels we know about and remove them if they
17181765
// get reorg'd out.
17191766
// c) it's unclear how to do so without exposing ourselves to massive DoS risk.
1720-
Self::remove_channel_in_nodes(&mut nodes, &entry.get(), short_channel_id);
1767+
self.remove_channel_in_nodes(&mut nodes, &entry.get(), short_channel_id);
17211768
*entry.get_mut() = channel_info;
17221769
} else {
17231770
return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreDuplicateGossip});
@@ -1734,9 +1781,13 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
17341781
node_entry.into_mut().channels.push(short_channel_id);
17351782
},
17361783
IndexedMapEntry::Vacant(node_entry) => {
1784+
let mut removed_node_counters = self.removed_node_counters.lock().unwrap();
1785+
let node_counter = removed_node_counters.pop()
1786+
.unwrap_or(self.next_node_counter.fetch_add(1, Ordering::Relaxed) as u32);
17371787
node_entry.insert(NodeInfo {
17381788
channels: vec!(short_channel_id),
17391789
announcement_info: None,
1790+
node_counter,
17401791
});
17411792
}
17421793
};
@@ -1855,7 +1906,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
18551906
if let Some(chan) = channels.remove(&short_channel_id) {
18561907
let mut nodes = self.nodes.write().unwrap();
18571908
self.removed_channels.lock().unwrap().insert(short_channel_id, current_time_unix);
1858-
Self::remove_channel_in_nodes(&mut nodes, &chan, short_channel_id);
1909+
self.remove_channel_in_nodes(&mut nodes, &chan, short_channel_id);
18591910
}
18601911
}
18611912

@@ -1874,6 +1925,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
18741925
let mut removed_nodes = self.removed_nodes.lock().unwrap();
18751926

18761927
if let Some(node) = nodes.remove(&node_id) {
1928+
let mut removed_node_counters = self.removed_node_counters.lock().unwrap();
18771929
for scid in node.channels.iter() {
18781930
if let Some(chan_info) = channels.remove(scid) {
18791931
let other_node_id = if node_id == chan_info.node_one { chan_info.node_two } else { chan_info.node_one };
@@ -1882,12 +1934,14 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
18821934
*scid != *chan_id
18831935
});
18841936
if other_node_entry.get().channels.is_empty() {
1937+
removed_node_counters.push(other_node_entry.get().node_counter);
18851938
other_node_entry.remove_entry();
18861939
}
18871940
}
18881941
removed_channels.insert(*scid, current_time_unix);
18891942
}
18901943
}
1944+
removed_node_counters.push(node.node_counter);
18911945
removed_nodes.insert(node_id, current_time_unix);
18921946
}
18931947
}
@@ -1963,7 +2017,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
19632017
let mut nodes = self.nodes.write().unwrap();
19642018
for scid in scids_to_remove {
19652019
let info = channels.remove(&scid).expect("We just accessed this scid, it should be present");
1966-
Self::remove_channel_in_nodes(&mut nodes, &info, scid);
2020+
self.remove_channel_in_nodes(&mut nodes, &info, scid);
19672021
self.removed_channels.lock().unwrap().insert(scid, Some(current_time_unix));
19682022
}
19692023
}
@@ -2145,14 +2199,15 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
21452199
Ok(())
21462200
}
21472201

2148-
fn remove_channel_in_nodes(nodes: &mut IndexedMap<NodeId, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
2202+
fn remove_channel_in_nodes(&self, nodes: &mut IndexedMap<NodeId, NodeInfo>, chan: &ChannelInfo, short_channel_id: u64) {
21492203
macro_rules! remove_from_node {
21502204
($node_id: expr) => {
21512205
if let IndexedMapEntry::Occupied(mut entry) = nodes.entry($node_id) {
21522206
entry.get_mut().channels.retain(|chan_id| {
21532207
short_channel_id != *chan_id
21542208
});
21552209
if entry.get().channels.is_empty() {
2210+
self.removed_node_counters.lock().unwrap().push(entry.get().node_counter);
21562211
entry.remove_entry();
21572212
}
21582213
} else {
@@ -3574,6 +3629,7 @@ pub(crate) mod tests {
35743629
let valid_node_info = NodeInfo {
35753630
channels: Vec::new(),
35763631
announcement_info: Some(valid_node_ann_info),
3632+
node_counter: 0,
35773633
};
35783634

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

0 commit comments

Comments
 (0)