17
17
solana_sdk:: {
18
18
clock:: { Epoch , Slot } ,
19
19
feature_set,
20
+ genesis_config:: ClusterType ,
20
21
native_token:: LAMPORTS_PER_SOL ,
21
22
pubkey:: Pubkey ,
22
23
signature:: { Keypair , Signer } ,
29
30
collections:: HashMap ,
30
31
iter:: repeat_with,
31
32
marker:: PhantomData ,
32
- net:: SocketAddr ,
33
+ net:: { IpAddr , SocketAddr } ,
33
34
sync:: { Arc , Mutex , RwLock } ,
34
35
time:: { Duration , Instant } ,
35
36
} ,
39
40
const DATA_PLANE_FANOUT : usize = 200 ;
40
41
pub ( crate ) const MAX_NUM_TURBINE_HOPS : usize = 4 ;
41
42
43
+ // Limit number of nodes per IP address.
44
+ const MAX_NUM_NODES_PER_IP_ADDRESS : usize = 10 ;
45
+
42
46
#[ derive( Debug , Error ) ]
43
47
pub enum Error {
44
48
#[ error( "Loopback from slot leader: {leader}, shred: {shred:?}" ) ]
@@ -81,9 +85,6 @@ pub struct ClusterNodesCache<T> {
81
85
pub struct RetransmitPeers < ' a > {
82
86
root_distance : usize , // distance from the root node
83
87
children : Vec < & ' a Node > ,
84
- // Maps tvu addresses to the first node
85
- // in the shuffle with the same address.
86
- addrs : HashMap < SocketAddr , Pubkey > , // tvu addresses
87
88
}
88
89
89
90
impl Node {
@@ -147,8 +148,12 @@ impl<T> ClusterNodes<T> {
147
148
}
148
149
149
150
impl ClusterNodes < BroadcastStage > {
150
- pub fn new ( cluster_info : & ClusterInfo , stakes : & HashMap < Pubkey , u64 > ) -> Self {
151
- new_cluster_nodes ( cluster_info, stakes)
151
+ pub fn new (
152
+ cluster_info : & ClusterInfo ,
153
+ cluster_type : ClusterType ,
154
+ stakes : & HashMap < Pubkey , u64 > ,
155
+ ) -> Self {
156
+ new_cluster_nodes ( cluster_info, cluster_type, stakes)
152
157
}
153
158
154
159
pub ( crate ) fn get_broadcast_peer ( & self , shred : & ShredId ) -> Option < & ContactInfo > {
@@ -168,16 +173,13 @@ impl ClusterNodes<RetransmitStage> {
168
173
let RetransmitPeers {
169
174
root_distance,
170
175
children,
171
- addrs,
172
176
} = self . get_retransmit_peers ( slot_leader, shred, fanout) ?;
173
177
let protocol = get_broadcast_protocol ( shred) ;
174
- let peers = children. into_iter ( ) . filter_map ( |node| {
175
- node. contact_info ( ) ?
176
- . tvu ( protocol)
177
- . ok ( )
178
- . filter ( |addr| addrs. get ( addr) == Some ( & node. pubkey ( ) ) )
179
- } ) ;
180
- Ok ( ( root_distance, peers. collect ( ) ) )
178
+ let peers = children
179
+ . into_iter ( )
180
+ . filter_map ( |node| node. contact_info ( ) ?. tvu ( protocol) . ok ( ) )
181
+ . collect ( ) ;
182
+ Ok ( ( root_distance, peers) )
181
183
}
182
184
183
185
pub fn get_retransmit_peers (
@@ -197,19 +199,10 @@ impl ClusterNodes<RetransmitStage> {
197
199
if let Some ( index) = self . index . get ( slot_leader) {
198
200
weighted_shuffle. remove_index ( * index) ;
199
201
}
200
- let mut addrs = HashMap :: < SocketAddr , Pubkey > :: with_capacity ( self . nodes . len ( ) ) ;
201
202
let mut rng = get_seeded_rng ( slot_leader, shred) ;
202
- let protocol = get_broadcast_protocol ( shred) ;
203
203
let nodes: Vec < _ > = weighted_shuffle
204
204
. shuffle ( & mut rng)
205
205
. map ( |index| & self . nodes [ index] )
206
- . inspect ( |node| {
207
- if let Some ( node) = node. contact_info ( ) {
208
- if let Ok ( addr) = node. tvu ( protocol) {
209
- addrs. entry ( addr) . or_insert ( * node. pubkey ( ) ) ;
210
- }
211
- }
212
- } )
213
206
. collect ( ) ;
214
207
let self_index = nodes
215
208
. iter ( )
@@ -228,7 +221,6 @@ impl ClusterNodes<RetransmitStage> {
228
221
Ok ( RetransmitPeers {
229
222
root_distance,
230
223
children : peers. collect ( ) ,
231
- addrs,
232
224
} )
233
225
}
234
226
@@ -272,10 +264,11 @@ impl ClusterNodes<RetransmitStage> {
272
264
273
265
pub fn new_cluster_nodes < T : ' static > (
274
266
cluster_info : & ClusterInfo ,
267
+ cluster_type : ClusterType ,
275
268
stakes : & HashMap < Pubkey , u64 > ,
276
269
) -> ClusterNodes < T > {
277
270
let self_pubkey = cluster_info. id ( ) ;
278
- let nodes = get_nodes ( cluster_info, stakes) ;
271
+ let nodes = get_nodes ( cluster_info, cluster_type , stakes) ;
279
272
let index: HashMap < _ , _ > = nodes
280
273
. iter ( )
281
274
. enumerate ( )
@@ -298,8 +291,21 @@ pub fn new_cluster_nodes<T: 'static>(
298
291
299
292
// All staked nodes + other known tvu-peers + the node itself;
300
293
// sorted by (stake, pubkey) in descending order.
301
- fn get_nodes ( cluster_info : & ClusterInfo , stakes : & HashMap < Pubkey , u64 > ) -> Vec < Node > {
294
+ fn get_nodes (
295
+ cluster_info : & ClusterInfo ,
296
+ cluster_type : ClusterType ,
297
+ stakes : & HashMap < Pubkey , u64 > ,
298
+ ) -> Vec < Node > {
302
299
let self_pubkey = cluster_info. id ( ) ;
300
+ let should_dedup_addrs = match cluster_type {
301
+ ClusterType :: Development => false ,
302
+ ClusterType :: Devnet | ClusterType :: Testnet | ClusterType :: MainnetBeta => true ,
303
+ } ;
304
+ // Maps IP addresses to number of nodes at that IP address.
305
+ let mut counts = {
306
+ let capacity = if should_dedup_addrs { stakes. len ( ) } else { 0 } ;
307
+ HashMap :: < IpAddr , usize > :: with_capacity ( capacity)
308
+ } ;
303
309
// The local node itself.
304
310
std:: iter:: once ( {
305
311
let stake = stakes. get ( & self_pubkey) . copied ( ) . unwrap_or_default ( ) ;
@@ -328,6 +334,30 @@ fn get_nodes(cluster_info: &ClusterInfo, stakes: &HashMap<Pubkey, u64>) -> Vec<N
328
334
// Since sorted_by_key is stable, in case of duplicates, this
329
335
// will keep nodes with contact-info.
330
336
. dedup_by ( |a, b| a. pubkey ( ) == b. pubkey ( ) )
337
+ . filter_map ( |node| {
338
+ if !should_dedup_addrs
339
+ || node
340
+ . contact_info ( )
341
+ . and_then ( |node| node. tvu ( Protocol :: UDP ) . ok ( ) )
342
+ . map ( |addr| {
343
+ * counts
344
+ . entry ( addr. ip ( ) )
345
+ . and_modify ( |count| * count += 1 )
346
+ . or_insert ( 1 )
347
+ } )
348
+ <= Some ( MAX_NUM_NODES_PER_IP_ADDRESS )
349
+ {
350
+ Some ( node)
351
+ } else {
352
+ // If the node is not staked, drop it entirely. Otherwise, keep the
353
+ // pubkey for deterministic shuffle, but strip the contact-info so
354
+ // that no more packets are sent to this node.
355
+ ( node. stake > 0u64 ) . then ( || Node {
356
+ node : NodeId :: from ( node. pubkey ( ) ) ,
357
+ stake : node. stake ,
358
+ } )
359
+ }
360
+ } )
331
361
. collect ( )
332
362
}
333
363
@@ -446,6 +476,7 @@ impl<T: 'static> ClusterNodesCache<T> {
446
476
}
447
477
let nodes = Arc :: new ( new_cluster_nodes :: < T > (
448
478
cluster_info,
479
+ root_bank. cluster_type ( ) ,
449
480
& epoch_staked_nodes. unwrap_or_default ( ) ,
450
481
) ) ;
451
482
* entry = Some ( ( Instant :: now ( ) , Arc :: clone ( & nodes) ) ) ;
@@ -583,7 +614,8 @@ mod tests {
583
614
let ( nodes, stakes, cluster_info) = make_test_cluster ( & mut rng, 1_000 , None ) ;
584
615
// ClusterInfo::tvu_peers excludes the node itself.
585
616
assert_eq ! ( cluster_info. tvu_peers( ) . len( ) , nodes. len( ) - 1 ) ;
586
- let cluster_nodes = new_cluster_nodes :: < RetransmitStage > ( & cluster_info, & stakes) ;
617
+ let cluster_nodes =
618
+ new_cluster_nodes :: < RetransmitStage > ( & cluster_info, ClusterType :: Development , & stakes) ;
587
619
// All nodes with contact-info should be in the index.
588
620
// Staked nodes with no contact-info should be included.
589
621
assert ! ( cluster_nodes. nodes. len( ) > nodes. len( ) ) ;
@@ -618,7 +650,8 @@ mod tests {
618
650
let ( nodes, stakes, cluster_info) = make_test_cluster ( & mut rng, 1_000 , None ) ;
619
651
// ClusterInfo::tvu_peers excludes the node itself.
620
652
assert_eq ! ( cluster_info. tvu_peers( ) . len( ) , nodes. len( ) - 1 ) ;
621
- let cluster_nodes = ClusterNodes :: < BroadcastStage > :: new ( & cluster_info, & stakes) ;
653
+ let cluster_nodes =
654
+ ClusterNodes :: < BroadcastStage > :: new ( & cluster_info, ClusterType :: Development , & stakes) ;
622
655
// All nodes with contact-info should be in the index.
623
656
// Excluding this node itself.
624
657
// Staked nodes with no contact-info should be included.
0 commit comments