shadow_load_testing/
swarm.rs1use shadow_core::{PeerId, PeerInfo};
4use dht::RoutingTable;
5
6pub struct VirtualSwarm {
8 peers: Vec<VirtualPeer>,
9}
10
11pub struct VirtualPeer {
13 id: PeerId,
14 routing_table: RoutingTable,
15}
16
17impl VirtualSwarm {
18 pub fn new(count: usize) -> Self {
20 let peers: Vec<VirtualPeer> = (0..count)
21 .map(|i| {
22 let id = PeerId::random();
23 let routing_table = RoutingTable::new(id, 20);
24 VirtualPeer { id, routing_table }
25 })
26 .collect();
27
28 VirtualSwarm { peers }
29 }
30
31 pub fn peer_count(&self) -> usize {
33 self.peers.len()
34 }
35
36 pub fn peer_ids(&self) -> Vec<PeerId> {
38 self.peers.iter().map(|p| p.id).collect()
39 }
40
41 pub fn peer(&self, index: usize) -> Option<&VirtualPeer> {
43 self.peers.get(index)
44 }
45
46 pub fn peer_mut(&mut self, index: usize) -> Option<&mut VirtualPeer> {
48 self.peers.get_mut(index)
49 }
50
51 pub fn bootstrap(&mut self, connections_per_peer: usize) {
53 let ids: Vec<PeerId> = self.peer_ids();
54 let count = ids.len();
55
56 for i in 0..count {
57 let step = std::cmp::max(1, count / connections_per_peer);
58 for k in 1..=connections_per_peer {
59 let j = (i + k * step) % count;
60 if j != i {
61 let peer_info = PeerInfo::new(
62 ids[j],
63 vec![format!("127.0.0.1:{}", 10000 + j)],
64 [0u8; 32],
65 [0u8; 32],
66 );
67 let _ = self.peers[i].routing_table.add_peer(peer_info);
68 }
69 }
70 }
71 }
72
73 pub fn avg_routing_table_size(&self) -> f64 {
75 if self.peers.is_empty() {
76 return 0.0;
77 }
78 let total: usize = self.peers.iter()
79 .map(|p| p.routing_table.peer_count())
80 .sum();
81 total as f64 / self.peers.len() as f64
82 }
83
84 pub fn find_closest_global(&self, target: &PeerId, k: usize) -> Vec<PeerId> {
86 let mut all_ids = self.peer_ids();
87 all_ids.sort_by(|a, b| {
88 let dist_a = a.xor_distance(target);
89 let dist_b = b.xor_distance(target);
90 dist_a.cmp(&dist_b)
91 });
92 all_ids.truncate(k);
93 all_ids
94 }
95
96 pub fn iterative_lookup(&self, start: usize, target: &PeerId, k: usize) -> Vec<PeerInfo> {
98 if let Some(peer) = self.peers.get(start) {
99 peer.routing_table.find_closest(target, k)
100 } else {
101 vec![]
102 }
103 }
104}
105
106impl VirtualPeer {
107 pub fn id(&self) -> PeerId {
108 self.id
109 }
110
111 pub fn routing_table(&self) -> &RoutingTable {
112 &self.routing_table
113 }
114
115 pub fn routing_table_mut(&mut self) -> &mut RoutingTable {
116 &mut self.routing_table
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_swarm_creation() {
126 let swarm = VirtualSwarm::new(100);
127 assert_eq!(swarm.peer_count(), 100);
128 assert_eq!(swarm.peer_ids().len(), 100);
129 }
130
131 #[test]
132 fn test_swarm_bootstrap() {
133 let mut swarm = VirtualSwarm::new(50);
134 swarm.bootstrap(5);
135 let avg = swarm.avg_routing_table_size();
136 assert!(avg > 0.0, "Should have peers in routing tables after bootstrap");
137 }
138
139 #[test]
140 fn test_swarm_lookup() {
141 let mut swarm = VirtualSwarm::new(100);
142 swarm.bootstrap(10);
143 let target = PeerId::random();
144 let closest = swarm.find_closest_global(&target, 20);
145 assert_eq!(closest.len(), 20);
146 }
147
148 #[test]
149 fn test_unique_peer_ids() {
150 let swarm = VirtualSwarm::new(1000);
151 let ids = swarm.peer_ids();
152 let unique: std::collections::HashSet<_> = ids.iter().collect();
153 assert_eq!(unique.len(), 1000, "All peer IDs should be unique");
154 }
155
156 #[test]
157 fn test_large_swarm() {
158 let swarm = VirtualSwarm::new(10_000);
159 assert_eq!(swarm.peer_count(), 10_000);
160 }
161
162 #[test]
163 fn test_iterative_lookup() {
164 let mut swarm = VirtualSwarm::new(50);
165 swarm.bootstrap(5);
166 let target = PeerId::random();
167 let results = swarm.iterative_lookup(0, &target, 5);
168 assert!(!results.is_empty() || swarm.peer(0).unwrap().routing_table().peer_count() == 0);
170 }
171}