@@ -42,7 +42,6 @@ use crate::sync::Mutex;
42
42
use crate :: sync:: { LockTestExt , RwLock , RwLockReadGuard } ;
43
43
use core:: ops:: { Bound , Deref } ;
44
44
use core:: str:: FromStr ;
45
- #[ cfg( feature = "std" ) ]
46
45
use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
47
46
use core:: { cmp, fmt} ;
48
47
@@ -184,6 +183,8 @@ pub struct NetworkGraph<L: Deref> where L::Target: Logger {
184
183
// Lock order: channels -> nodes
185
184
channels : RwLock < IndexedMap < u64 , ChannelInfo > > ,
186
185
nodes : RwLock < IndexedMap < NodeId , NodeInfo > > ,
186
+ removed_node_counters : Mutex < Vec < u32 > > ,
187
+ next_node_counter : AtomicUsize ,
187
188
// Lock order: removed_channels -> removed_nodes
188
189
//
189
190
// NOTE: In the following `removed_*` maps, we use seconds since UNIX epoch to track time instead
@@ -1368,15 +1369,27 @@ impl Readable for NodeAlias {
1368
1369
}
1369
1370
}
1370
1371
1371
- #[ derive( Clone , Debug , PartialEq , Eq ) ]
1372
+ #[ derive( Clone , Debug , Eq ) ]
1372
1373
/// Details about a node in the network, known from the network announcement.
1373
1374
pub struct NodeInfo {
1374
1375
/// All valid channels a node has announced
1375
1376
pub channels : Vec < u64 > ,
1376
1377
/// More information about a node from node_announcement.
1377
1378
/// Optional because we store a Node entry after learning about it from
1378
1379
/// 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
+ }
1380
1393
}
1381
1394
1382
1395
impl NodeInfo {
@@ -1446,6 +1459,7 @@ impl Readable for NodeInfo {
1446
1459
Ok ( NodeInfo {
1447
1460
announcement_info : announcement_info_wrap. map ( |w| w. 0 ) ,
1448
1461
channels,
1462
+ node_counter : u32:: max_value ( ) ,
1449
1463
} )
1450
1464
}
1451
1465
}
@@ -1455,6 +1469,8 @@ const MIN_SERIALIZATION_VERSION: u8 = 1;
1455
1469
1456
1470
impl < L : Deref > Writeable for NetworkGraph < L > where L :: Target : Logger {
1457
1471
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
1472
+ self . test_node_counter_consistency ( ) ;
1473
+
1458
1474
write_ver_prefix ! ( writer, SERIALIZATION_VERSION , MIN_SERIALIZATION_VERSION ) ;
1459
1475
1460
1476
self . chain_hash . write ( writer) ?;
@@ -1493,11 +1509,15 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
1493
1509
channels. insert ( chan_id, chan_info) ;
1494
1510
}
1495
1511
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 ) ; }
1496
1515
// In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
1497
1516
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 {
1499
1518
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 ;
1501
1521
nodes. insert ( node_id, node_info) ;
1502
1522
}
1503
1523
@@ -1512,6 +1532,8 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
1512
1532
logger,
1513
1533
channels : RwLock :: new ( channels) ,
1514
1534
nodes : RwLock :: new ( nodes) ,
1535
+ removed_node_counters : Mutex :: new ( Vec :: new ( ) ) ,
1536
+ next_node_counter : AtomicUsize :: new ( nodes_count as usize ) ,
1515
1537
last_rapid_gossip_sync_timestamp : Mutex :: new ( last_rapid_gossip_sync_timestamp) ,
1516
1538
removed_nodes : Mutex :: new ( new_hash_map ( ) ) ,
1517
1539
removed_channels : Mutex :: new ( new_hash_map ( ) ) ,
@@ -1557,15 +1579,42 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1557
1579
logger,
1558
1580
channels : RwLock :: new ( IndexedMap :: new ( ) ) ,
1559
1581
nodes : RwLock :: new ( IndexedMap :: new ( ) ) ,
1582
+ next_node_counter : AtomicUsize :: new ( 0 ) ,
1583
+ removed_node_counters : Mutex :: new ( Vec :: new ( ) ) ,
1560
1584
last_rapid_gossip_sync_timestamp : Mutex :: new ( None ) ,
1561
1585
removed_channels : Mutex :: new ( new_hash_map ( ) ) ,
1562
1586
removed_nodes : Mutex :: new ( new_hash_map ( ) ) ,
1563
1587
pending_checks : utxo:: PendingChecks :: new ( ) ,
1564
1588
}
1565
1589
}
1566
1590
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
+
1567
1615
/// Returns a read-only view of the network graph.
1568
1616
pub fn read_only ( & ' _ self ) -> ReadOnlyNetworkGraph < ' _ > {
1617
+ self . test_node_counter_consistency ( ) ;
1569
1618
let channels = self . channels . read ( ) . unwrap ( ) ;
1570
1619
let nodes = self . nodes . read ( ) . unwrap ( ) ;
1571
1620
ReadOnlyNetworkGraph {
@@ -1752,7 +1801,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1752
1801
// b) we don't track UTXOs of channels we know about and remove them if they
1753
1802
// get reorg'd out.
1754
1803
// 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) ;
1756
1805
* entry. get_mut ( ) = channel_info;
1757
1806
} else {
1758
1807
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 {
1769
1818
node_entry. into_mut ( ) . channels . push ( short_channel_id) ;
1770
1819
} ,
1771
1820
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 ) ;
1772
1824
node_entry. insert ( NodeInfo {
1773
1825
channels : vec ! ( short_channel_id) ,
1774
1826
announcement_info : None ,
1827
+ node_counter,
1775
1828
} ) ;
1776
1829
}
1777
1830
} ;
@@ -1890,7 +1943,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1890
1943
if let Some ( chan) = channels. remove ( & short_channel_id) {
1891
1944
let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1892
1945
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) ;
1894
1947
}
1895
1948
}
1896
1949
@@ -1909,6 +1962,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1909
1962
let mut removed_nodes = self . removed_nodes . lock ( ) . unwrap ( ) ;
1910
1963
1911
1964
if let Some ( node) = nodes. remove ( & node_id) {
1965
+ let mut removed_node_counters = self . removed_node_counters . lock ( ) . unwrap ( ) ;
1912
1966
for scid in node. channels . iter ( ) {
1913
1967
if let Some ( chan_info) = channels. remove ( scid) {
1914
1968
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 {
1917
1971
* scid != * chan_id
1918
1972
} ) ;
1919
1973
if other_node_entry. get ( ) . channels . is_empty ( ) {
1974
+ removed_node_counters. push ( other_node_entry. get ( ) . node_counter ) ;
1920
1975
other_node_entry. remove_entry ( ) ;
1921
1976
}
1922
1977
}
1923
1978
removed_channels. insert ( * scid, current_time_unix) ;
1924
1979
}
1925
1980
}
1981
+ removed_node_counters. push ( node. node_counter ) ;
1926
1982
removed_nodes. insert ( node_id, current_time_unix) ;
1927
1983
}
1928
1984
}
@@ -1998,7 +2054,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
1998
2054
let mut nodes = self . nodes . write ( ) . unwrap ( ) ;
1999
2055
for scid in scids_to_remove {
2000
2056
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) ;
2002
2058
self . removed_channels . lock ( ) . unwrap ( ) . insert ( scid, Some ( current_time_unix) ) ;
2003
2059
}
2004
2060
}
@@ -2180,14 +2236,15 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
2180
2236
Ok ( ( ) )
2181
2237
}
2182
2238
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 ) {
2184
2240
macro_rules! remove_from_node {
2185
2241
( $node_id: expr) => {
2186
2242
if let IndexedMapEntry :: Occupied ( mut entry) = nodes. entry( $node_id) {
2187
2243
entry. get_mut( ) . channels. retain( |chan_id| {
2188
2244
short_channel_id != * chan_id
2189
2245
} ) ;
2190
2246
if entry. get( ) . channels. is_empty( ) {
2247
+ self . removed_node_counters. lock( ) . unwrap( ) . push( entry. get( ) . node_counter) ;
2191
2248
entry. remove_entry( ) ;
2192
2249
}
2193
2250
} else {
@@ -3604,6 +3661,7 @@ pub(crate) mod tests {
3604
3661
let valid_node_info = NodeInfo {
3605
3662
channels : Vec :: new ( ) ,
3606
3663
announcement_info : Some ( valid_node_ann_info) ,
3664
+ node_counter : 0 ,
3607
3665
} ;
3608
3666
3609
3667
let mut encoded_valid_node_info = Vec :: new ( ) ;
0 commit comments