@@ -935,6 +935,10 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
935935 /// MIN_SYNC_COMMITTEE_PEERS
936936 /// number should be set low as an absolute lower bound to maintain peers on the sync
937937 /// committees.
938+ /// - Do not prune trusted peers. NOTE: This means if a user has more trusted peers than the
939+ /// excess peer limit, all of the following logic is subverted as we will not prune any peers.
940+ /// Also, the more trusted peers a user has, the less room Lighthouse has to efficiently manage
941+ /// its peers across the subnets.
938942 ///
939943 /// Prune peers in the following order:
940944 /// 1. Remove worst scoring peers
@@ -965,7 +969,9 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
965969 . read( )
966970 . worst_connected_peers( )
967971 . iter( )
968- . filter( |( _, info) | !info. has_future_duty( ) && $filter( * info) )
972+ . filter( |( _, info) | {
973+ !info. has_future_duty( ) && !info. is_trusted( ) && $filter( * info)
974+ } )
969975 {
970976 if peers_to_prune. len( )
971977 >= connected_peer_count. saturating_sub( self . target_peers)
@@ -1015,8 +1021,8 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
10151021 > = HashMap :: new ( ) ;
10161022
10171023 for ( peer_id, info) in self . network_globals . peers . read ( ) . connected_peers ( ) {
1018- // Ignore peers we are already pruning
1019- if peers_to_prune. contains ( peer_id) {
1024+ // Ignore peers we trust or that we are already pruning
1025+ if info . is_trusted ( ) || peers_to_prune. contains ( peer_id) {
10201026 continue ;
10211027 }
10221028
@@ -1313,25 +1319,47 @@ mod tests {
13131319 ..Default :: default ( )
13141320 } ;
13151321 let log = build_log ( slog:: Level :: Debug , false ) ;
1316- let globals = NetworkGlobals :: new_test_globals ( & log) ;
1322+ let globals = NetworkGlobals :: new_test_globals ( vec ! [ ] , & log) ;
1323+ PeerManager :: new ( config, Arc :: new ( globals) , & log) . unwrap ( )
1324+ }
1325+
1326+ async fn build_peer_manager_with_trusted_peers (
1327+ trusted_peers : Vec < PeerId > ,
1328+ target_peer_count : usize ,
1329+ ) -> PeerManager < E > {
1330+ let config = config:: Config {
1331+ target_peer_count,
1332+ discovery_enabled : false ,
1333+ ..Default :: default ( )
1334+ } ;
1335+ let log = build_log ( slog:: Level :: Debug , false ) ;
1336+ let globals = NetworkGlobals :: new_test_globals ( trusted_peers, & log) ;
13171337 PeerManager :: new ( config, Arc :: new ( globals) , & log) . unwrap ( )
13181338 }
13191339
13201340 #[ tokio:: test]
13211341 async fn test_peer_manager_disconnects_correctly_during_heartbeat ( ) {
1322- let mut peer_manager = build_peer_manager ( 3 ) . await ;
1323-
1324- // Create 5 peers to connect to.
1342+ // Create 6 peers to connect to with a target of 3.
13251343 // 2 will be outbound-only, and have the lowest score.
1344+ // 1 will be a trusted peer.
1345+ // The other 3 will be ingoing peers.
1346+
1347+ // We expect this test to disconnect from 3 peers. 1 from the outbound peer (the other must
1348+ // remain due to the outbound peer limit) and 2 from the ingoing peers (the trusted peer
1349+ // should remain connected).
13261350 let peer0 = PeerId :: random ( ) ;
13271351 let peer1 = PeerId :: random ( ) ;
13281352 let peer2 = PeerId :: random ( ) ;
13291353 let outbound_only_peer1 = PeerId :: random ( ) ;
13301354 let outbound_only_peer2 = PeerId :: random ( ) ;
1355+ let trusted_peer = PeerId :: random ( ) ;
1356+
1357+ let mut peer_manager = build_peer_manager_with_trusted_peers ( vec ! [ trusted_peer] , 3 ) . await ;
13311358
13321359 peer_manager. inject_connect_ingoing ( & peer0, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13331360 peer_manager. inject_connect_ingoing ( & peer1, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13341361 peer_manager. inject_connect_ingoing ( & peer2, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
1362+ peer_manager. inject_connect_ingoing ( & trusted_peer, "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) , None ) ;
13351363 peer_manager. inject_connect_outgoing (
13361364 & outbound_only_peer1,
13371365 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
@@ -1361,7 +1389,7 @@ mod tests {
13611389 . add_to_score ( -2.0 ) ;
13621390
13631391 // Check initial connected peers.
1364- assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 5 ) ;
1392+ assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 6 ) ;
13651393
13661394 peer_manager. heartbeat ( ) ;
13671395
@@ -1380,8 +1408,22 @@ mod tests {
13801408 . read( )
13811409 . is_connected( & outbound_only_peer2) ) ;
13821410
1411+ // The trusted peer remains connected
1412+ assert ! ( peer_manager
1413+ . network_globals
1414+ . peers
1415+ . read( )
1416+ . is_connected( & trusted_peer) ) ;
1417+
13831418 peer_manager. heartbeat ( ) ;
13841419
1420+ // The trusted peer remains connected, even after subsequent heartbeats.
1421+ assert ! ( peer_manager
1422+ . network_globals
1423+ . peers
1424+ . read( )
1425+ . is_connected( & trusted_peer) ) ;
1426+
13851427 // Check that if we are at target number of peers, we do not disconnect any.
13861428 assert_eq ! ( peer_manager. network_globals. connected_or_dialing_peers( ) , 3 ) ;
13871429 }
@@ -2126,7 +2168,7 @@ mod tests {
21262168 #[ cfg( test) ]
21272169 mod property_based_tests {
21282170 use crate :: peer_manager:: config:: DEFAULT_TARGET_PEERS ;
2129- use crate :: peer_manager:: tests:: build_peer_manager ;
2171+ use crate :: peer_manager:: tests:: build_peer_manager_with_trusted_peers ;
21302172 use crate :: rpc:: MetaData ;
21312173 use libp2p:: PeerId ;
21322174 use quickcheck:: { Arbitrary , Gen , TestResult } ;
@@ -2137,10 +2179,12 @@ mod tests {
21372179
21382180 #[ derive( Clone , Debug ) ]
21392181 struct PeerCondition {
2182+ peer_id : PeerId ,
21402183 outgoing : bool ,
21412184 attestation_net_bitfield : Vec < bool > ,
21422185 sync_committee_net_bitfield : Vec < bool > ,
21432186 score : f64 ,
2187+ trusted : bool ,
21442188 gossipsub_score : f64 ,
21452189 }
21462190
@@ -2165,10 +2209,12 @@ mod tests {
21652209 } ;
21662210
21672211 PeerCondition {
2212+ peer_id : PeerId :: random ( ) ,
21682213 outgoing : bool:: arbitrary ( g) ,
21692214 attestation_net_bitfield,
21702215 sync_committee_net_bitfield,
21712216 score : f64:: arbitrary ( g) ,
2217+ trusted : bool:: arbitrary ( g) ,
21722218 gossipsub_score : f64:: arbitrary ( g) ,
21732219 }
21742220 }
@@ -2180,26 +2226,36 @@ mod tests {
21802226 if peer_conditions. len ( ) < target_peer_count {
21812227 return TestResult :: discard ( ) ;
21822228 }
2229+ let trusted_peers: Vec < _ > = peer_conditions
2230+ . iter ( )
2231+ . filter_map ( |p| if p. trusted { Some ( p. peer_id ) } else { None } )
2232+ . collect ( ) ;
2233+ // If we have a high percentage of trusted peers, it is very difficult to reason about
2234+ // the expected results of the pruning.
2235+ if trusted_peers. len ( ) > peer_conditions. len ( ) / 3_usize {
2236+ return TestResult :: discard ( ) ;
2237+ }
21832238 let rt = Runtime :: new ( ) . unwrap ( ) ;
21842239
21852240 rt. block_on ( async move {
2186- let mut peer_manager = build_peer_manager ( target_peer_count) . await ;
2241+ // Collect all the trusted peers
2242+ let mut peer_manager =
2243+ build_peer_manager_with_trusted_peers ( trusted_peers, target_peer_count) . await ;
21872244
21882245 // Create peers based on the randomly generated conditions.
21892246 for condition in & peer_conditions {
2190- let peer = PeerId :: random ( ) ;
21912247 let mut attnets = crate :: types:: EnrAttestationBitfield :: < E > :: new ( ) ;
21922248 let mut syncnets = crate :: types:: EnrSyncCommitteeBitfield :: < E > :: new ( ) ;
21932249
21942250 if condition. outgoing {
21952251 peer_manager. inject_connect_outgoing (
2196- & peer ,
2252+ & condition . peer_id ,
21972253 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
21982254 None ,
21992255 ) ;
22002256 } else {
22012257 peer_manager. inject_connect_ingoing (
2202- & peer ,
2258+ & condition . peer_id ,
22032259 "/ip4/0.0.0.0" . parse ( ) . unwrap ( ) ,
22042260 None ,
22052261 ) ;
@@ -2220,22 +2276,51 @@ mod tests {
22202276 } ;
22212277
22222278 let mut peer_db = peer_manager. network_globals . peers . write ( ) ;
2223- let peer_info = peer_db. peer_info_mut ( & peer ) . unwrap ( ) ;
2279+ let peer_info = peer_db. peer_info_mut ( & condition . peer_id ) . unwrap ( ) ;
22242280 peer_info. set_meta_data ( MetaData :: V2 ( metadata) ) ;
22252281 peer_info. set_gossipsub_score ( condition. gossipsub_score ) ;
22262282 peer_info. add_to_score ( condition. score ) ;
22272283
22282284 for subnet in peer_info. long_lived_subnets ( ) {
2229- peer_db. add_subscription ( & peer , subnet) ;
2285+ peer_db. add_subscription ( & condition . peer_id , subnet) ;
22302286 }
22312287 }
22322288
22332289 // Perform the heartbeat.
22342290 peer_manager. heartbeat ( ) ;
22352291
2236- TestResult :: from_bool (
2292+ // The minimum number of connected peers cannot be less than the target peer count
2293+ // or submitted peers.
2294+
2295+ let expected_peer_count = target_peer_count. min ( peer_conditions. len ( ) ) ;
2296+ // Trusted peers could make this larger however.
2297+ let no_of_trusted_peers = peer_conditions
2298+ . iter ( )
2299+ . filter ( |condition| condition. trusted )
2300+ . count ( ) ;
2301+ let expected_peer_count = expected_peer_count. max ( no_of_trusted_peers) ;
2302+
2303+ let target_peer_condition =
22372304 peer_manager. network_globals . connected_or_dialing_peers ( )
2238- == target_peer_count. min ( peer_conditions. len ( ) ) ,
2305+ == expected_peer_count;
2306+
2307+ // It could be that we reach our target outbound limit and are unable to prune any
2308+ // extra, which violates the target_peer_condition.
2309+ let outbound_peers = peer_manager. network_globals . connected_outbound_only_peers ( ) ;
2310+ let hit_outbound_limit = outbound_peers == peer_manager. target_outbound_peers ( ) ;
2311+
2312+ // No trusted peers should be disconnected
2313+ let trusted_peer_disconnected = peer_conditions. iter ( ) . any ( |condition| {
2314+ condition. trusted
2315+ && !peer_manager
2316+ . network_globals
2317+ . peers
2318+ . read ( )
2319+ . is_connected ( & condition. peer_id )
2320+ } ) ;
2321+
2322+ TestResult :: from_bool (
2323+ ( target_peer_condition || hit_outbound_limit) && !trusted_peer_disconnected,
22392324 )
22402325 } )
22412326 }
0 commit comments