@@ -205,40 +205,49 @@ pub fn build_swarm(
205205 . subscribe ( & aggregation_topic)
206206 . unwrap ( ) ;
207207
208- // Compute the set of subnets to subscribe to.
209- // Validators subscribe for gossipsub mesh health; aggregators additionally
210- // subscribe to any explicitly requested subnets.
211- let validator_subnets: HashSet < u64 > = config
212- . validator_ids
213- . iter ( )
214- . map ( |vid| vid % config. attestation_committee_count )
215- . collect ( ) ;
216-
217- let mut subscribe_subnets: HashSet < u64 > = validator_subnets. clone ( ) ;
218-
208+ // Aggregators subscribe to attestation subnets to receive unaggregated
209+ // attestations. Non-aggregators don't need to subscribe; they publish via
210+ // gossipsub fanout.
219211 if config. is_aggregator {
212+ let mut aggregate_subnets: HashSet < u64 > = config
213+ . validator_ids
214+ . iter ( )
215+ . map ( |vid| vid % config. attestation_committee_count )
216+ . collect ( ) ;
220217 if let Some ( ref explicit_ids) = config. aggregate_subnet_ids {
221- subscribe_subnets . extend ( explicit_ids) ;
218+ aggregate_subnets . extend ( explicit_ids) ;
222219 }
223220 // Aggregator with no validators and no explicit subnets: fallback to subnet 0
224- if subscribe_subnets. is_empty ( ) {
225- subscribe_subnets. insert ( 0 ) ;
221+ if aggregate_subnets. is_empty ( ) {
222+ aggregate_subnets. insert ( 0 ) ;
223+ }
224+ for & subnet_id in & aggregate_subnets {
225+ let topic = attestation_subnet_topic ( subnet_id) ;
226+ swarm. behaviour_mut ( ) . gossipsub . subscribe ( & topic) ?;
227+ info ! ( subnet_id, "Subscribed to attestation subnet" ) ;
226228 }
227229 }
228230
229- // Report lowest validator subnet for backward-compatible metric
230- let metric_subnet = validator_subnets. iter ( ) . copied ( ) . min ( ) . unwrap_or ( 0 ) ;
231- metrics:: set_attestation_committee_subnet ( metric_subnet) ;
232-
233- // Build topics and subscribe
231+ // Build topic cache (avoids string allocation on every publish).
232+ // Includes validator subnets and any explicit aggregate_subnet_ids.
234233 let mut attestation_topics: HashMap < u64 , libp2p:: gossipsub:: IdentTopic > = HashMap :: new ( ) ;
235- for & subnet_id in & subscribe_subnets {
236- let topic = attestation_subnet_topic ( subnet_id) ;
237- swarm. behaviour_mut ( ) . gossipsub . subscribe ( & topic) ?;
238- info ! ( subnet_id, "Subscribed to attestation subnet" ) ;
239- attestation_topics. insert ( subnet_id, topic) ;
234+ for & vid in & config. validator_ids {
235+ let subnet_id = vid % config. attestation_committee_count ;
236+ attestation_topics
237+ . entry ( subnet_id)
238+ . or_insert_with ( || attestation_subnet_topic ( subnet_id) ) ;
239+ }
240+ if let Some ( ref explicit_ids) = config. aggregate_subnet_ids {
241+ for & subnet_id in explicit_ids {
242+ attestation_topics
243+ . entry ( subnet_id)
244+ . or_insert_with ( || attestation_subnet_topic ( subnet_id) ) ;
245+ }
240246 }
241247
248+ let metric_subnet = attestation_topics. keys ( ) . copied ( ) . min ( ) . unwrap_or ( 0 ) ;
249+ metrics:: set_attestation_committee_subnet ( metric_subnet) ;
250+
242251 info ! ( socket=%config. listening_socket, "P2P node started" ) ;
243252
244253 Ok ( BuiltSwarm {
0 commit comments