@@ -42,7 +42,6 @@ use crate::sync::Mutex;
4242use crate :: sync:: { LockTestExt , RwLock , RwLockReadGuard } ;
4343use core:: ops:: { Bound , Deref } ;
4444use core:: str:: FromStr ;
45- #[ cfg( feature = "std" ) ]
4645use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
4746use 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.
13731374pub 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
13821395impl 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
14561470impl < 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