@@ -129,7 +129,9 @@ pub struct PeerDiscovery<ST: CertificateSignatureRecoverable> {
129129 pub epoch_validators : BTreeMap < Epoch , BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > > ,
130130 // initial bootstrap peers set in config file
131131 pub initial_bootstrap_peers : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
132- // pinned full nodes are dedicated and prioritized full nodes passed in from config that will not be pruned
132+ // prioritized full nodes for secondary raptorcast, set in config file
133+ pub prioritized_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
134+ // pinned full nodes contains dedicated and prioritized full nodes, and initial bootstrap peers that will not be pruned
133135 pub pinned_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
134136 // mapping of node IDs to their corresponding name records
135137 pub routing_info : BTreeMap < NodeId < CertificateSignaturePubKey < ST > > , MonadNameRecord < ST > > ,
@@ -156,6 +158,8 @@ pub struct PeerDiscovery<ST: CertificateSignatureRecoverable> {
156158 pub min_num_peers : usize ,
157159 // maximum number of peers before pruning
158160 pub max_num_peers : usize ,
161+ // maximum number of peers in a raptorcast group
162+ pub max_group_size : usize ,
159163 // secondary raptorcast setting: enable publisher mode when self is a validator
160164 pub enable_publisher : bool ,
161165 // secondary raptorcast setting: enable client mode when self is a full node
@@ -170,13 +174,15 @@ pub struct PeerDiscoveryBuilder<ST: CertificateSignatureRecoverable> {
170174 pub current_epoch : Epoch ,
171175 pub epoch_validators : BTreeMap < Epoch , BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > > ,
172176 pub pinned_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
177+ pub prioritized_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
173178 pub bootstrap_peers : BTreeMap < NodeId < CertificateSignaturePubKey < ST > > , MonadNameRecord < ST > > ,
174179 pub refresh_period : Duration ,
175180 pub request_timeout : Duration ,
176181 pub unresponsive_prune_threshold : u32 ,
177182 pub last_participation_prune_threshold : Round ,
178183 pub min_num_peers : usize ,
179184 pub max_num_peers : usize ,
185+ pub max_group_size : usize ,
180186 pub enable_publisher : bool ,
181187 pub enable_client : bool ,
182188 pub rng : ChaCha8Rng ,
@@ -235,6 +241,7 @@ impl<ST: CertificateSignatureRecoverable> PeerDiscoveryAlgoBuilder for PeerDisco
235241 . keys ( )
236242 . cloned ( )
237243 . collect :: < BTreeSet < _ > > ( ) ,
244+ prioritized_full_nodes : self . prioritized_full_nodes ,
238245 pinned_full_nodes : self . pinned_full_nodes ,
239246 routing_info : Default :: default ( ) ,
240247 participation_info : Default :: default ( ) ,
@@ -247,6 +254,7 @@ impl<ST: CertificateSignatureRecoverable> PeerDiscoveryAlgoBuilder for PeerDisco
247254 last_participation_prune_threshold : self . last_participation_prune_threshold ,
248255 min_num_peers : self . min_num_peers ,
249256 max_num_peers : self . max_num_peers ,
257+ max_group_size : self . max_group_size ,
250258 enable_publisher : self . enable_publisher ,
251259 enable_client : self . enable_client ,
252260 rng : self . rng ,
@@ -643,8 +651,7 @@ where
643651 // we still respond with pong even if peer list is full
644652 let mut peer_list_full = false ;
645653 if self . routing_info . len ( ) + self . pending_queue . len ( ) >= self . max_num_peers
646- && !self . check_validator_membership ( & from)
647- && !self . pinned_full_nodes . contains ( & from)
654+ && !self . is_pinned_node ( & from)
648655 && !self . routing_info . contains_key ( & from)
649656 {
650657 debug ! (
@@ -1089,6 +1096,28 @@ where
10891096 return cmds;
10901097 }
10911098
1099+ // drop request if incoming request is a public full node and max_group_size is already reached
1100+ if !self . prioritized_full_nodes . contains ( & from) {
1101+ let connected_public_full_nodes = self
1102+ . participation_info
1103+ . iter ( )
1104+ . filter ( |( node_id, info) | {
1105+ info. status == SecondaryRaptorcastConnectionStatus :: Connected
1106+ && !self . prioritized_full_nodes . contains ( node_id)
1107+ } )
1108+ . count ( ) ;
1109+
1110+ if connected_public_full_nodes + self . prioritized_full_nodes . len ( )
1111+ >= self . max_group_size
1112+ {
1113+ debug ! (
1114+ ?from,
1115+ "connected full nodes already exceeds max group size, dropping request"
1116+ ) ;
1117+ return cmds;
1118+ }
1119+ }
1120+
10921121 if let Some ( info) = self . participation_info . get_mut ( & from) {
10931122 info. status = SecondaryRaptorcastConnectionStatus :: Connected ;
10941123 } else {
@@ -1154,7 +1183,6 @@ where
11541183 . filter_map ( |( node_id, info) | {
11551184 if self . current_round . max ( info. last_active ) - info. last_active
11561185 >= self . last_participation_prune_threshold
1157- && !self . is_pinned_node ( node_id)
11581186 {
11591187 Some ( * node_id)
11601188 } else {
@@ -1164,9 +1192,16 @@ where
11641192 . collect ( ) ;
11651193
11661194 for node_id in non_participating_nodes {
1167- debug ! ( ?node_id, "removing non-participating peer" ) ;
1168- self . participation_info . remove ( & node_id) ;
1169- self . routing_info . remove ( & node_id) ;
1195+ if self . is_pinned_node ( & node_id) {
1196+ debug ! ( ?node_id, "clearing participation info for pinned node" ) ;
1197+ if let Some ( info) = self . participation_info . get_mut ( & node_id) {
1198+ info. status = SecondaryRaptorcastConnectionStatus :: None ;
1199+ }
1200+ } else {
1201+ debug ! ( ?node_id, "removing non-participating peer" ) ;
1202+ self . participation_info . remove ( & node_id) ;
1203+ self . routing_info . remove ( & node_id) ;
1204+ }
11701205 }
11711206
11721207 // if number of peers above max number of peers, randomly choose a few full nodes and prune them from routing_info
@@ -1406,11 +1441,21 @@ where
14061441
14071442 fn update_pinned_nodes (
14081443 & mut self ,
1409- pinned_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
1444+ dedicated_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
1445+ prioritized_full_nodes : BTreeSet < NodeId < CertificateSignaturePubKey < ST > > > ,
14101446 ) -> Vec < PeerDiscoveryCommand < ST > > {
1411- debug ! ( ?pinned_nodes, "updating pinned nodes" ) ;
1447+ debug ! (
1448+ ?dedicated_full_nodes,
1449+ ?prioritized_full_nodes,
1450+ "updating pinned nodes"
1451+ ) ;
14121452
1413- self . pinned_full_nodes = pinned_nodes;
1453+ self . pinned_full_nodes = dedicated_full_nodes
1454+ . iter ( )
1455+ . chain ( prioritized_full_nodes. iter ( ) )
1456+ . cloned ( )
1457+ . collect ( ) ;
1458+ self . prioritized_full_nodes = prioritized_full_nodes;
14141459
14151460 Vec :: new ( )
14161461 }
@@ -1565,6 +1610,7 @@ mod tests {
15651610 epoch_validators : BTreeMap :: new ( ) ,
15661611 initial_bootstrap_peers : routing_info. keys ( ) . cloned ( ) . collect ( ) ,
15671612 pinned_full_nodes : BTreeSet :: new ( ) ,
1613+ prioritized_full_nodes : BTreeSet :: new ( ) ,
15681614 routing_info,
15691615 participation_info,
15701616 pending_queue : BTreeMap :: new ( ) ,
@@ -1576,6 +1622,7 @@ mod tests {
15761622 last_participation_prune_threshold : Round ( 5000 ) ,
15771623 min_num_peers : 5 ,
15781624 max_num_peers : 50 ,
1625+ max_group_size : 50 ,
15791626 enable_publisher : false ,
15801627 enable_client : false ,
15811628 rng : ChaCha8Rng :: seed_from_u64 ( 123456 ) ,
@@ -2234,12 +2281,16 @@ mod tests {
22342281
22352282 #[ test]
22362283 fn test_publisher_participation_info ( ) {
2237- let keys = create_keys :: < SignatureType > ( 2 ) ;
2284+ let keys = create_keys :: < SignatureType > ( 4 ) ;
22382285 let peer0 = & keys[ 0 ] ;
22392286 let peer1 = & keys[ 1 ] ;
2287+ let peer2 = & keys[ 2 ] ;
2288+ let peer3 = & keys[ 3 ] ;
22402289 let peer1_pubkey = NodeId :: new ( peer1. pubkey ( ) ) ;
2290+ let peer2_pubkey = NodeId :: new ( peer2. pubkey ( ) ) ;
2291+ let peer3_pubkey = NodeId :: new ( peer3. pubkey ( ) ) ;
22412292
2242- let mut state = generate_test_state ( peer0, vec ! [ peer1] ) ;
2293+ let mut state = generate_test_state ( peer0, vec ! [ peer1, peer2 , peer3 ] ) ;
22432294
22442295 // do not respond to full node raptorcast request if self is not a validator publisher
22452296 state. self_role = PeerDiscoveryRole :: ValidatorNone ;
@@ -2262,6 +2313,52 @@ mod tests {
22622313 message: PeerDiscoveryMessage :: FullNodeRaptorcastResponse
22632314 } ) ) ;
22642315 assert_eq ! ( state. get_secondary_fullnodes( ) , Vec :: from( [ peer1_pubkey] ) ) ;
2316+
2317+ // do not respond to full node raptorcast request if already exceeding max group size
2318+ state. max_group_size = 1 ;
2319+ let cmds = state. handle_full_node_raptorcast_request ( peer2_pubkey) ;
2320+ assert_eq ! (
2321+ state. participation_info. get( & peer2_pubkey) . unwrap( ) . status,
2322+ SecondaryRaptorcastConnectionStatus :: None
2323+ ) ;
2324+ assert_eq ! ( cmds. len( ) , 0 ) ;
2325+ assert_eq ! ( state. get_secondary_fullnodes( ) , Vec :: from( [ peer1_pubkey] ) ) ;
2326+
2327+ // prioritized full nodes are reserved a slot even if unconnected
2328+ state. prioritized_full_nodes . insert ( peer3_pubkey) ;
2329+ state. max_group_size = 2 ;
2330+ let cmds = state. handle_full_node_raptorcast_request ( peer2_pubkey) ;
2331+ // peer1 (connected) and peer3 (prioritized) took up the slots
2332+ // peer2 is still rejected
2333+ assert_eq ! (
2334+ state. participation_info. get( & peer1_pubkey) . unwrap( ) . status,
2335+ SecondaryRaptorcastConnectionStatus :: Connected
2336+ ) ;
2337+ assert_eq ! (
2338+ state. participation_info. get( & peer2_pubkey) . unwrap( ) . status,
2339+ SecondaryRaptorcastConnectionStatus :: None
2340+ ) ;
2341+ assert_eq ! (
2342+ state. participation_info. get( & peer3_pubkey) . unwrap( ) . status,
2343+ SecondaryRaptorcastConnectionStatus :: None
2344+ ) ;
2345+ assert_eq ! ( cmds. len( ) , 0 ) ;
2346+ assert_eq ! ( state. get_secondary_fullnodes( ) , Vec :: from( [ peer1_pubkey] ) ) ;
2347+
2348+ // a connected prioritized full node is only counted once towards max_group_size
2349+ state. handle_full_node_raptorcast_request ( peer3_pubkey) ;
2350+ assert_eq ! (
2351+ state. participation_info. get( & peer3_pubkey) . unwrap( ) . status,
2352+ SecondaryRaptorcastConnectionStatus :: Connected
2353+ ) ;
2354+ state. max_group_size = 3 ;
2355+ let cmds = state. handle_full_node_raptorcast_request ( peer2_pubkey) ;
2356+ // now peer2 is accepted as there are only 2 connections
2357+ assert_eq ! (
2358+ state. participation_info. get( & peer2_pubkey) . unwrap( ) . status,
2359+ SecondaryRaptorcastConnectionStatus :: Connected
2360+ ) ;
2361+ assert_eq ! ( cmds. len( ) , 1 ) ;
22652362 }
22662363
22672364 #[ test]
0 commit comments