@@ -940,6 +940,10 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
940940 /// MIN_SYNC_COMMITTEE_PEERS
941941 /// number should be set low as an absolute lower bound to maintain peers on the sync
942942 /// committees.
943+ /// - Do not prune trusted peers. NOTE: This means if a user has more trusted peers than the
944+ /// excess peer limit, all of the following logic is subverted as we will not prune any peers.
945+ /// Also, the more trusted peers a user has, the less room Lighthouse has to efficiently manage
946+ /// its peers across the subnets.
943947 ///
944948 /// Prune peers in the following order:
945949 /// 1. Remove worst scoring peers
@@ -970,7 +974,9 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
970974 . read( )
971975 . worst_connected_peers( )
972976 . iter( )
973- . filter( |( _, info) | !info. has_future_duty( ) && $filter( * info) )
977+ . filter( |( _, info) | {
978+ !info. has_future_duty( ) && !info. is_trusted( ) && $filter( * info)
979+ } )
974980 {
975981 if peers_to_prune. len( )
976982 >= connected_peer_count. saturating_sub( self . target_peers)
@@ -1020,8 +1026,8 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
10201026 > = HashMap :: new ( ) ;
10211027
10221028 for ( peer_id, info) in self . network_globals . peers . read ( ) . connected_peers ( ) {
1023- // Ignore peers we are already pruning
1024- if peers_to_prune. contains ( peer_id) {
1029+ // Ignore peers we trust or that we are already pruning
1030+ if info . is_trusted ( ) || peers_to_prune. contains ( peer_id) {
10251031 continue ;
10261032 }
10271033
@@ -1318,25 +1324,47 @@ mod tests {
13181324 ..Default :: default ( )
13191325 } ;
13201326 let log = build_log ( slog:: Level :: Debug , false ) ;
1321- let globals = NetworkGlobals :: new_test_globals ( & log) ;
1327+ let globals = NetworkGlobals :: new_test_globals ( vec ! [ ] , & log) ;
1328+ PeerManager :: new ( config, Arc :: new ( globals) , & log) . unwrap ( )
1329+ }
1330+
1331+ async fn build_peer_manager_with_trusted_peers (
1332+ trusted_peers : Vec < PeerId > ,
1333+ target_peer_count : usize ,
1334+ ) -> PeerManager < E > {
1335+ let config = config:: Config {
1336+ target_peer_count,
1337+ discovery_enabled : false ,
1338+ ..Default :: default ( )
1339+ } ;
1340+ let log = build_log ( slog:: Level :: Debug , false ) ;
1341+ let globals = NetworkGlobals :: new_test_globals ( trusted_peers, & log) ;
13221342 PeerManager :: new ( config, Arc :: new ( globals) , & log) . unwrap ( )
13231343 }
13241344
13251345 #[ tokio:: test]
13261346 async fn test_peer_manager_disconnects_correctly_during_heartbeat ( ) {
1327- let mut peer_manager = build_peer_manager ( 3 ) . await ;
1328-
1329- // Create 5 peers to connect to.
1347+ // Create 6 peers to connect to with a target of 3.
13301348 // 2 will be outbound-only, and have the lowest score.
1349+ // 1 will be a trusted peer.
1350+ // The other 3 will be ingoing peers.
1351+
1352+ // We expect this test to disconnect from 3 peers. 1 from the outbound peer (the other must
1353+ // remain due to the outbound peer limit) and 2 from the ingoing peers (the trusted peer
1354+ // should remain connected).
13311355 let peer0 = PeerId :: random ( ) ;
13321356 let peer1 = PeerId :: random ( ) ;
13331357 let peer2 = PeerId :: random ( ) ;
13341358 let outbound_only_peer1 = PeerId :: random ( ) ;
13351359 let outbound_only_peer2 = PeerId :: random ( ) ;
1360+ let trusted_peer = PeerId :: random ( ) ;
1361+
1362+ let mut peer_manager = build_peer_manager_with_trusted_peers ( vec ! [ trusted_peer] , 3 ) . await ;
13361363
13371364 peer_manager. inject_connect_ingoing ( & peer0, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13381365 peer_manager. inject_connect_ingoing ( & peer1, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13391366 peer_manager. inject_connect_ingoing ( & peer2, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
1367+ peer_manager. inject_connect_ingoing ( & trusted_peer, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13401368 peer_manager. inject_connect_outgoing (
13411369 & outbound_only_peer1,
13421370 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
@@ -1366,7 +1394,7 @@ mod tests {
13661394 . add_to_score ( -2.0 ) ;
13671395
13681396 // Check initial connected peers.
1369- assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 5 ) ;
1397+ assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 6 ) ;
13701398
13711399 peer_manager. heartbeat ( ) ;
13721400
@@ -1385,8 +1413,22 @@ mod tests {
13851413 . read( )
13861414 . is_connected( & outbound_only_peer2) ) ;
13871415
1416+ // The trusted peer remains connected
1417+ assert ! ( peer_manager
1418+ . network_globals
1419+ . peers
1420+ . read( )
1421+ . is_connected( & trusted_peer) ) ;
1422+
13881423 peer_manager. heartbeat ( ) ;
13891424
1425+ // The trusted peer remains connected, even after subsequent heartbeats.
1426+ assert ! ( peer_manager
1427+ . network_globals
1428+ . peers
1429+ . read( )
1430+ . is_connected( & trusted_peer) ) ;
1431+
13901432 // Check that if we are at target number of peers, we do not disconnect any.
13911433 assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 3 ) ;
13921434 }
@@ -2131,7 +2173,7 @@ mod tests {
21312173 #[ cfg( test) ]
21322174 mod property_based_tests {
21332175 use crate :: peer_manager:: config:: DEFAULT_TARGET_PEERS ;
2134- use crate :: peer_manager:: tests:: build_peer_manager ;
2176+ use crate :: peer_manager:: tests:: build_peer_manager_with_trusted_peers ;
21352177 use crate :: rpc:: MetaData ;
21362178 use libp2p:: PeerId ;
21372179 use quickcheck:: { Arbitrary , Gen , TestResult } ;
@@ -2142,10 +2184,12 @@ mod tests {
21422184
21432185 #[ derive( Clone , Debug ) ]
21442186 struct PeerCondition {
2187+ peer_id : PeerId ,
21452188 outgoing : bool ,
21462189 attestation_net_bitfield : Vec < bool > ,
21472190 sync_committee_net_bitfield : Vec < bool > ,
21482191 score : f64 ,
2192+ trusted : bool ,
21492193 gossipsub_score : f64 ,
21502194 }
21512195
@@ -2170,10 +2214,12 @@ mod tests {
21702214 } ;
21712215
21722216 PeerCondition {
2217+ peer_id : PeerId :: random ( ) ,
21732218 outgoing : bool:: arbitrary ( g) ,
21742219 attestation_net_bitfield,
21752220 sync_committee_net_bitfield,
21762221 score : f64:: arbitrary ( g) ,
2222+ trusted : bool:: arbitrary ( g) ,
21772223 gossipsub_score : f64:: arbitrary ( g) ,
21782224 }
21792225 }
@@ -2185,26 +2231,36 @@ mod tests {
21852231 if peer_conditions. len ( ) < target_peer_count {
21862232 return TestResult :: discard ( ) ;
21872233 }
2234+ let trusted_peers: Vec < _ > = peer_conditions
2235+ . iter ( )
2236+ . filter_map ( |p| if p. trusted { Some ( p. peer_id ) } else { None } )
2237+ . collect ( ) ;
2238+ // If we have a high percentage of trusted peers, it is very difficult to reason about
2239+ // the expected results of the pruning.
2240+ if trusted_peers. len ( ) > peer_conditions. len ( ) / 3_usize {
2241+ return TestResult :: discard ( ) ;
2242+ }
21882243 let rt = Runtime :: new ( ) . unwrap ( ) ;
21892244
21902245 rt. block_on ( async move {
2191- let mut peer_manager = build_peer_manager ( target_peer_count) . await ;
2246+ // Collect all the trusted peers
2247+ let mut peer_manager =
2248+ build_peer_manager_with_trusted_peers ( trusted_peers, target_peer_count) . await ;
21922249
21932250 // Create peers based on the randomly generated conditions.
21942251 for condition in & peer_conditions {
2195- let peer = PeerId :: random ( ) ;
21962252 let mut attnets = crate :: types:: EnrAttestationBitfield :: < E > :: new ( ) ;
21972253 let mut syncnets = crate :: types:: EnrSyncCommitteeBitfield :: < E > :: new ( ) ;
21982254
21992255 if condition. outgoing {
22002256 peer_manager. inject_connect_outgoing (
2201- & peer ,
2257+ & condition . peer_id ,
22022258 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
22032259 None ,
22042260 ) ;
22052261 } else {
22062262 peer_manager. inject_connect_ingoing (
2207- & peer ,
2263+ & condition . peer_id ,
22082264 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
22092265 None ,
22102266 ) ;
@@ -2225,22 +2281,51 @@ mod tests {
22252281 } ;
22262282
22272283 let mut peer_db = peer_manager. network_globals . peers . write ( ) ;
2228- let peer_info = peer_db. peer_info_mut ( & peer ) . unwrap ( ) ;
2284+ let peer_info = peer_db. peer_info_mut ( & condition . peer_id ) . unwrap ( ) ;
22292285 peer_info. set_meta_data ( MetaData :: V2 ( metadata) ) ;
22302286 peer_info. set_gossipsub_score ( condition. gossipsub_score ) ;
22312287 peer_info. add_to_score ( condition. score ) ;
22322288
22332289 for subnet in peer_info. long_lived_subnets ( ) {
2234- peer_db. add_subscription ( & peer , subnet) ;
2290+ peer_db. add_subscription ( & condition . peer_id , subnet) ;
22352291 }
22362292 }
22372293
22382294 // Perform the heartbeat.
22392295 peer_manager. heartbeat ( ) ;
22402296
2241- TestResult :: from_bool (
2297+ // The minimum number of connected peers cannot be less than the target peer count
2298+ // or submitted peers.
2299+
2300+ let expected_peer_count = target_peer_count. min ( peer_conditions. len ( ) ) ;
2301+ // Trusted peers could make this larger however.
2302+ let no_of_trusted_peers = peer_conditions
2303+ . iter ( )
2304+ . filter ( |condition| condition. trusted )
2305+ . count ( ) ;
2306+ let expected_peer_count = expected_peer_count. max ( no_of_trusted_peers) ;
2307+
2308+ let target_peer_condition =
22422309 peer_manager. network_globals . connected_or_dialing_peers ( )
2243- == target_peer_count. min ( peer_conditions. len ( ) ) ,
2310+ == expected_peer_count;
2311+
2312+ // It could be that we reach our target outbound limit and are unable to prune any
2313+ // extra, which violates the target_peer_condition.
2314+ let outbound_peers = peer_manager. network_globals . connected_outbound_only_peers ( ) ;
2315+ let hit_outbound_limit = outbound_peers == peer_manager. target_outbound_peers ( ) ;
2316+
2317+ // No trusted peers should be disconnected
2318+ let trusted_peer_disconnected = peer_conditions. iter ( ) . any ( |condition| {
2319+ condition. trusted
2320+ && !peer_manager
2321+ . network_globals
2322+ . peers
2323+ . read ( )
2324+ . is_connected ( & condition. peer_id )
2325+ } ) ;
2326+
2327+ TestResult :: from_bool (
2328+ ( target_peer_condition || hit_outbound_limit) && !trusted_peer_disconnected,
22442329 )
22452330 } )
22462331 }
0 commit comments