1use crate::PeerId;
8use anyhow::{anyhow, Result};
9use ed25519_dalek::{Keypair, PublicKey, Signature, Signer, Verifier};
10use sha2::{Digest, Sha256};
11use std::collections::HashMap;
12use std::net::Ipv6Addr;
13use std::time::{Duration, SystemTime, UNIX_EPOCH};
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct IPv6NodeID {
19 pub node_id: Vec<u8>,
21 pub ipv6_addr: Ipv6Addr,
23 pub public_key: Vec<u8>,
25 pub signature: Vec<u8>,
27 pub timestamp_secs: u64,
29 pub salt: Vec<u8>,
31}
32
33#[derive(Debug, Clone)]
35pub struct IPDiversityConfig {
36 pub max_nodes_per_64: usize,
38 pub max_nodes_per_48: usize,
40 pub max_nodes_per_32: usize,
42 pub max_nodes_per_asn: usize,
44 pub enable_geolocation_check: bool,
46 pub min_geographic_diversity: usize,
48}
49
50#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
52pub struct IPAnalysis {
53 pub subnet_64: Ipv6Addr,
55 pub subnet_48: Ipv6Addr,
57 pub subnet_32: Ipv6Addr,
59 pub asn: Option<u32>,
61 pub country: Option<String>,
63 pub is_hosting_provider: bool,
65 pub is_vpn_provider: bool,
67 pub reputation_score: f64,
69}
70
71#[derive(Debug, Clone)]
73pub struct NodeReputation {
74 pub peer_id: PeerId,
76 pub response_rate: f64,
78 pub response_time: Duration,
80 pub consistency_score: f64,
82 pub uptime_estimate: Duration,
84 pub routing_accuracy: f64,
86 pub last_seen: SystemTime,
88 pub interaction_count: u64,
90}
91
92impl Default for IPDiversityConfig {
93 fn default() -> Self {
94 Self {
95 max_nodes_per_64: 1,
96 max_nodes_per_48: 3,
97 max_nodes_per_32: 10,
98 max_nodes_per_asn: 20,
99 enable_geolocation_check: true,
100 min_geographic_diversity: 3,
101 }
102 }
103}
104
105impl IPv6NodeID {
106 pub fn generate(ipv6_addr: Ipv6Addr, keypair: &Keypair) -> Result<Self> {
108 let mut rng = rand::thread_rng();
109 let mut salt = vec![0u8; 16];
110 rand::RngCore::fill_bytes(&mut rng, &mut salt);
111
112 let timestamp = SystemTime::now();
113 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
114 let public_key = keypair.public.to_bytes().to_vec();
115
116 let mut hasher = Sha256::new();
118 hasher.update(ipv6_addr.octets());
119 hasher.update(&public_key);
120 hasher.update(&salt);
121 hasher.update(×tamp_secs.to_le_bytes());
122 let node_id = hasher.finalize().to_vec();
123
124 let mut message_to_sign = Vec::new();
126 message_to_sign.extend_from_slice(&ipv6_addr.octets());
127 message_to_sign.extend_from_slice(&public_key);
128 message_to_sign.extend_from_slice(&salt);
129 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
130
131 let signature = keypair.sign(&message_to_sign).to_bytes().to_vec();
132
133 Ok(IPv6NodeID {
134 node_id,
135 ipv6_addr,
136 public_key,
137 signature,
138 timestamp_secs,
139 salt,
140 })
141 }
142
143 pub fn verify(&self) -> Result<bool> {
145 let mut hasher = Sha256::new();
147 hasher.update(self.ipv6_addr.octets());
148 hasher.update(&self.public_key);
149 hasher.update(&self.salt);
150 hasher.update(&self.timestamp_secs.to_le_bytes());
151 let expected_node_id = hasher.finalize();
152
153 if expected_node_id.as_slice() != &self.node_id {
155 return Ok(false);
156 }
157
158 if self.public_key.len() != 32 {
160 return Ok(false);
161 }
162 if self.signature.len() != 64 {
163 return Ok(false);
164 }
165
166 let mut pk_bytes = [0u8; 32];
167 pk_bytes.copy_from_slice(&self.public_key);
168 let public_key = PublicKey::from_bytes(&pk_bytes)
169 .map_err(|e| anyhow!("Invalid public key: {}", e))?;
170
171 let mut sig_bytes = [0u8; 64];
172 sig_bytes.copy_from_slice(&self.signature);
173 let signature = Signature::from_bytes(&sig_bytes)
174 .map_err(|e| anyhow!("Invalid signature: {}", e))?;
175
176 let mut message_to_verify = Vec::new();
177 message_to_verify.extend_from_slice(&self.ipv6_addr.octets());
178 message_to_verify.extend_from_slice(&self.public_key);
179 message_to_verify.extend_from_slice(&self.salt);
180 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
181
182 match public_key.verify(&message_to_verify, &signature) {
183 Ok(_) => Ok(true),
184 Err(_) => Ok(false),
185 }
186 }
187
188 pub fn extract_subnet_64(&self) -> Ipv6Addr {
190 let octets = self.ipv6_addr.octets();
191 let mut subnet = [0u8; 16];
192 subnet[..8].copy_from_slice(&octets[..8]); Ipv6Addr::from(subnet)
194 }
195
196 pub fn extract_subnet_48(&self) -> Ipv6Addr {
198 let octets = self.ipv6_addr.octets();
199 let mut subnet = [0u8; 16];
200 subnet[..6].copy_from_slice(&octets[..6]); Ipv6Addr::from(subnet)
202 }
203
204 pub fn extract_subnet_32(&self) -> Ipv6Addr {
206 let octets = self.ipv6_addr.octets();
207 let mut subnet = [0u8; 16];
208 subnet[..4].copy_from_slice(&octets[..4]); Ipv6Addr::from(subnet)
210 }
211}
212
213#[derive(Debug)]
215pub struct IPDiversityEnforcer {
216 config: IPDiversityConfig,
217 subnet_64_counts: HashMap<Ipv6Addr, usize>,
218 subnet_48_counts: HashMap<Ipv6Addr, usize>,
219 subnet_32_counts: HashMap<Ipv6Addr, usize>,
220 asn_counts: HashMap<u32, usize>,
221 country_counts: HashMap<String, usize>,
222}
223
224impl IPDiversityEnforcer {
225 pub fn new(config: IPDiversityConfig) -> Self {
227 Self {
228 config,
229 subnet_64_counts: HashMap::new(),
230 subnet_48_counts: HashMap::new(),
231 subnet_32_counts: HashMap::new(),
232 asn_counts: HashMap::new(),
233 country_counts: HashMap::new(),
234 }
235 }
236
237 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
239 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
240 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
241 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
242
243 let asn = None;
245
246 let country = None;
248
249 let is_hosting_provider = false;
251 let is_vpn_provider = false;
252
253 let reputation_score = 0.5;
255
256 Ok(IPAnalysis {
257 subnet_64,
258 subnet_48,
259 subnet_32,
260 asn,
261 country,
262 is_hosting_provider,
263 is_vpn_provider,
264 reputation_score,
265 })
266 }
267
268 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
270 let (limit_64, limit_48, limit_32, limit_asn) = if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
272 (
274 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
275 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
276 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
277 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
278 )
279 } else {
280 (
282 self.config.max_nodes_per_64,
283 self.config.max_nodes_per_48,
284 self.config.max_nodes_per_32,
285 self.config.max_nodes_per_asn,
286 )
287 };
288
289 if let Some(&count) = self.subnet_64_counts.get(&ip_analysis.subnet_64) {
291 if count >= limit_64 {
292 return false;
293 }
294 }
295
296 if let Some(&count) = self.subnet_48_counts.get(&ip_analysis.subnet_48) {
298 if count >= limit_48 {
299 return false;
300 }
301 }
302
303 if let Some(&count) = self.subnet_32_counts.get(&ip_analysis.subnet_32) {
305 if count >= limit_32 {
306 return false;
307 }
308 }
309
310 if let Some(asn) = ip_analysis.asn {
312 if let Some(&count) = self.asn_counts.get(&asn) {
313 if count >= limit_asn {
314 return false;
315 }
316 }
317 }
318
319 true
320 }
321
322 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
324 if !self.can_accept_node(ip_analysis) {
325 return Err(anyhow!("IP diversity limits exceeded"));
326 }
327
328 *self.subnet_64_counts.entry(ip_analysis.subnet_64).or_insert(0) += 1;
330 *self.subnet_48_counts.entry(ip_analysis.subnet_48).or_insert(0) += 1;
331 *self.subnet_32_counts.entry(ip_analysis.subnet_32).or_insert(0) += 1;
332
333 if let Some(asn) = ip_analysis.asn {
334 *self.asn_counts.entry(asn).or_insert(0) += 1;
335 }
336
337 if let Some(ref country) = ip_analysis.country {
338 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
339 }
340
341 Ok(())
342 }
343
344 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
346 if let Some(count) = self.subnet_64_counts.get_mut(&ip_analysis.subnet_64) {
347 *count = count.saturating_sub(1);
348 if *count == 0 {
349 self.subnet_64_counts.remove(&ip_analysis.subnet_64);
350 }
351 }
352
353 if let Some(count) = self.subnet_48_counts.get_mut(&ip_analysis.subnet_48) {
354 *count = count.saturating_sub(1);
355 if *count == 0 {
356 self.subnet_48_counts.remove(&ip_analysis.subnet_48);
357 }
358 }
359
360 if let Some(count) = self.subnet_32_counts.get_mut(&ip_analysis.subnet_32) {
361 *count = count.saturating_sub(1);
362 if *count == 0 {
363 self.subnet_32_counts.remove(&ip_analysis.subnet_32);
364 }
365 }
366
367 if let Some(asn) = ip_analysis.asn {
368 if let Some(count) = self.asn_counts.get_mut(&asn) {
369 *count = count.saturating_sub(1);
370 if *count == 0 {
371 self.asn_counts.remove(&asn);
372 }
373 }
374 }
375
376 if let Some(ref country) = ip_analysis.country {
377 if let Some(count) = self.country_counts.get_mut(country) {
378 *count = count.saturating_sub(1);
379 if *count == 0 {
380 self.country_counts.remove(country);
381 }
382 }
383 }
384 }
385
386 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
388 let octets = addr.octets();
389 let mut subnet = [0u8; 16];
390
391 let bytes_to_copy = (prefix_len / 8) as usize;
392 let remaining_bits = prefix_len % 8;
393
394 if bytes_to_copy < 16 {
396 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
397 } else {
398 subnet.copy_from_slice(&octets);
399 }
400
401 if remaining_bits > 0 && bytes_to_copy < 16 {
403 let mask = 0xFF << (8 - remaining_bits);
404 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
405 }
406
407 Ipv6Addr::from(subnet)
408 }
409
410 pub fn get_diversity_stats(&self) -> DiversityStats {
412 DiversityStats {
413 total_64_subnets: self.subnet_64_counts.len(),
414 total_48_subnets: self.subnet_48_counts.len(),
415 total_32_subnets: self.subnet_32_counts.len(),
416 total_asns: self.asn_counts.len(),
417 total_countries: self.country_counts.len(),
418 max_nodes_per_64: self.subnet_64_counts.values().max().copied().unwrap_or(0),
419 max_nodes_per_48: self.subnet_48_counts.values().max().copied().unwrap_or(0),
420 max_nodes_per_32: self.subnet_32_counts.values().max().copied().unwrap_or(0),
421 }
422 }
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct DiversityStats {
428 pub total_64_subnets: usize,
430 pub total_48_subnets: usize,
432 pub total_32_subnets: usize,
434 pub total_asns: usize,
436 pub total_countries: usize,
438 pub max_nodes_per_64: usize,
440 pub max_nodes_per_48: usize,
442 pub max_nodes_per_32: usize,
444}
445
446#[derive(Debug)]
448pub struct ReputationManager {
449 reputations: HashMap<PeerId, NodeReputation>,
450 reputation_decay: f64,
451 min_reputation: f64,
452}
453
454impl ReputationManager {
455 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
457 Self {
458 reputations: HashMap::new(),
459 reputation_decay,
460 min_reputation,
461 }
462 }
463
464 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
466 self.reputations.get(peer_id)
467 }
468
469 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
471 let reputation = self.reputations.entry(peer_id.clone()).or_insert_with(|| {
472 NodeReputation {
473 peer_id: peer_id.clone(),
474 response_rate: 0.5,
475 response_time: Duration::from_millis(500),
476 consistency_score: 0.5,
477 uptime_estimate: Duration::from_secs(0),
478 routing_accuracy: 0.5,
479 last_seen: SystemTime::now(),
480 interaction_count: 0,
481 }
482 });
483
484 let alpha = 0.3; if success {
488 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
489 } else {
490 reputation.response_rate = reputation.response_rate * (1.0 - alpha);
491 }
492
493 let response_time_ms = response_time.as_millis() as f64;
495 let current_response_ms = reputation.response_time.as_millis() as f64;
496 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
497 reputation.response_time = Duration::from_millis(new_response_ms as u64);
498
499 reputation.last_seen = SystemTime::now();
500 reputation.interaction_count += 1;
501 }
502
503 pub fn apply_decay(&mut self) {
505 let now = SystemTime::now();
506
507 self.reputations.retain(|_, reputation| {
508 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
509 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
511 reputation.response_rate *= decay_factor;
512 reputation.consistency_score *= decay_factor;
513 reputation.routing_accuracy *= decay_factor;
514
515 reputation.response_rate > self.min_reputation / 10.0
517 } else {
518 true
519 }
520 });
521 }
522}
523
524pub mod security_types {
526 use super::*;
527
528 pub struct KeyPair {
530 inner: Keypair,
531 }
532
533 impl KeyPair {
534 pub fn generate() -> Self {
536 let mut csprng = rand::rngs::OsRng {};
537 let keypair = Keypair::generate(&mut csprng);
538 KeyPair { inner: keypair }
539 }
540
541 pub fn inner(&self) -> &Keypair {
543 &self.inner
544 }
545
546 pub fn public_key_bytes(&self) -> [u8; 32] {
548 self.inner.public.to_bytes()
549 }
550
551 pub fn sign(&self, message: &[u8]) -> [u8; 64] {
553 self.inner.sign(message).to_bytes()
554 }
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561
562 fn create_test_keypair() -> Keypair {
563 let mut csprng = rand::rngs::OsRng {};
564 Keypair::generate(&mut csprng)
565 }
566
567 fn create_test_ipv6() -> Ipv6Addr {
568 Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334)
569 }
570
571 fn create_test_diversity_config() -> IPDiversityConfig {
572 IPDiversityConfig {
573 max_nodes_per_64: 1,
574 max_nodes_per_48: 3,
575 max_nodes_per_32: 10,
576 max_nodes_per_asn: 20,
577 enable_geolocation_check: true,
578 min_geographic_diversity: 3,
579 }
580 }
581
582 #[test]
583 fn test_ipv6_node_id_generation() -> Result<()> {
584 let keypair = create_test_keypair();
585 let ipv6_addr = create_test_ipv6();
586
587 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
588
589 assert_eq!(node_id.ipv6_addr, ipv6_addr);
590 assert_eq!(node_id.public_key.len(), 32);
591 assert_eq!(node_id.signature.len(), 64);
592 assert_eq!(node_id.node_id.len(), 32); assert_eq!(node_id.salt.len(), 16);
594 assert!(node_id.timestamp_secs > 0);
595
596 Ok(())
597 }
598
599 #[test]
600 fn test_ipv6_node_id_verification() -> Result<()> {
601 let keypair = create_test_keypair();
602 let ipv6_addr = create_test_ipv6();
603
604 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
605 let is_valid = node_id.verify()?;
606
607 assert!(is_valid);
608
609 Ok(())
610 }
611
612 #[test]
613 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
614 let keypair = create_test_keypair();
615 let ipv6_addr = create_test_ipv6();
616
617 let mut node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
618
619 node_id.node_id[0] ^= 0xFF;
621 let is_valid = node_id.verify()?;
622 assert!(!is_valid);
623
624 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &keypair)?;
626 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
628 assert!(!is_valid2);
629
630 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &keypair)?;
632 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
634 assert!(!is_valid3);
635
636 Ok(())
637 }
638
639 #[test]
640 fn test_ipv6_subnet_extraction() -> Result<()> {
641 let keypair = create_test_keypair();
642 let ipv6_addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334);
643
644 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
645
646 let subnet_64 = node_id.extract_subnet_64();
648 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
649 assert_eq!(subnet_64, expected_64);
650
651 let subnet_48 = node_id.extract_subnet_48();
653 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
654 assert_eq!(subnet_48, expected_48);
655
656 let subnet_32 = node_id.extract_subnet_32();
658 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
659 assert_eq!(subnet_32, expected_32);
660
661 Ok(())
662 }
663
664 #[test]
665 fn test_ip_diversity_config_default() {
666 let config = IPDiversityConfig::default();
667
668 assert_eq!(config.max_nodes_per_64, 1);
669 assert_eq!(config.max_nodes_per_48, 3);
670 assert_eq!(config.max_nodes_per_32, 10);
671 assert_eq!(config.max_nodes_per_asn, 20);
672 assert!(config.enable_geolocation_check);
673 assert_eq!(config.min_geographic_diversity, 3);
674 }
675
676 #[test]
677 fn test_ip_diversity_enforcer_creation() {
678 let config = create_test_diversity_config();
679 let enforcer = IPDiversityEnforcer::new(config.clone());
680
681 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
682 assert_eq!(enforcer.subnet_64_counts.len(), 0);
683 assert_eq!(enforcer.subnet_48_counts.len(), 0);
684 assert_eq!(enforcer.subnet_32_counts.len(), 0);
685 }
686
687 #[test]
688 fn test_ip_analysis() -> Result<()> {
689 let config = create_test_diversity_config();
690 let enforcer = IPDiversityEnforcer::new(config);
691
692 let ipv6_addr = create_test_ipv6();
693 let analysis = enforcer.analyze_ip(ipv6_addr)?;
694
695 assert_eq!(analysis.subnet_64, IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64));
696 assert_eq!(analysis.subnet_48, IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48));
697 assert_eq!(analysis.subnet_32, IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32));
698 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
701 assert!(!analysis.is_vpn_provider);
702 assert_eq!(analysis.reputation_score, 0.5);
703
704 Ok(())
705 }
706
707 #[test]
708 fn test_can_accept_node_basic() -> Result<()> {
709 let config = create_test_diversity_config();
710 let enforcer = IPDiversityEnforcer::new(config);
711
712 let ipv6_addr = create_test_ipv6();
713 let analysis = enforcer.analyze_ip(ipv6_addr)?;
714
715 assert!(enforcer.can_accept_node(&analysis));
717
718 Ok(())
719 }
720
721 #[test]
722 fn test_add_and_remove_node() -> Result<()> {
723 let config = create_test_diversity_config();
724 let mut enforcer = IPDiversityEnforcer::new(config);
725
726 let ipv6_addr = create_test_ipv6();
727 let analysis = enforcer.analyze_ip(ipv6_addr)?;
728
729 enforcer.add_node(&analysis)?;
731 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
732 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
733 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
734
735 enforcer.remove_node(&analysis);
737 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
738 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
739 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
740
741 Ok(())
742 }
743
744 #[test]
745 fn test_diversity_limits_enforcement() -> Result<()> {
746 let config = create_test_diversity_config();
747 let mut enforcer = IPDiversityEnforcer::new(config);
748
749 let ipv6_addr1 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334);
750 let ipv6_addr2 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
753 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
754
755 assert!(enforcer.can_accept_node(&analysis1));
757 enforcer.add_node(&analysis1)?;
758
759 assert!(!enforcer.can_accept_node(&analysis2));
761
762 let result = enforcer.add_node(&analysis2);
764 assert!(result.is_err());
765 assert!(result.unwrap_err().to_string().contains("IP diversity limits exceeded"));
766
767 Ok(())
768 }
769
770 #[test]
771 fn test_hosting_provider_stricter_limits() -> Result<()> {
772 let config = IPDiversityConfig {
773 max_nodes_per_64: 4, max_nodes_per_48: 8,
775 ..create_test_diversity_config()
776 };
777 let mut enforcer = IPDiversityEnforcer::new(config);
778
779 let ipv6_addr = create_test_ipv6();
780 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
781 analysis.is_hosting_provider = true;
782
783 assert!(enforcer.can_accept_node(&analysis));
785 enforcer.add_node(&analysis)?;
786
787 let ipv6_addr2 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335);
789 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
790 analysis2.is_hosting_provider = true;
791 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
794 enforcer.add_node(&analysis2)?;
795
796 let ipv6_addr3 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336);
798 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
799 analysis3.is_hosting_provider = true;
800 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
803
804 Ok(())
805 }
806
807 #[test]
808 fn test_diversity_stats() -> Result<()> {
809 let config = create_test_diversity_config();
810 let mut enforcer = IPDiversityEnforcer::new(config);
811
812 let addresses = [
814 Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334),
815 Ipv6Addr::new(0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334), Ipv6Addr::new(0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334), ];
818
819 for addr in addresses {
820 let analysis = enforcer.analyze_ip(addr)?;
821 enforcer.add_node(&analysis)?;
822 }
823
824 let stats = enforcer.get_diversity_stats();
825 assert_eq!(stats.total_64_subnets, 3);
826 assert_eq!(stats.total_48_subnets, 3);
827 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
829 assert_eq!(stats.max_nodes_per_48, 1);
830 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
833 }
834
835 #[test]
836 fn test_extract_subnet_prefix() {
837 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334);
838
839 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
841 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
842 assert_eq!(prefix_64, expected_64);
843
844 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
846 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
847 assert_eq!(prefix_48, expected_48);
848
849 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
851 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
852 assert_eq!(prefix_32, expected_32);
853
854 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
856 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
857 assert_eq!(prefix_56, expected_56);
858
859 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
861 assert_eq!(prefix_128, addr);
862 }
863
864 #[test]
865 fn test_reputation_manager_creation() {
866 let manager = ReputationManager::new(0.1, 0.1);
867 assert_eq!(manager.reputation_decay, 0.1);
868 assert_eq!(manager.min_reputation, 0.1);
869 assert_eq!(manager.reputations.len(), 0);
870 }
871
872 #[test]
873 fn test_reputation_get_nonexistent() {
874 let manager = ReputationManager::new(0.1, 0.1);
875 let peer_id = "test_peer".to_string();
876
877 let reputation = manager.get_reputation(&peer_id);
878 assert!(reputation.is_none());
879 }
880
881 #[test]
882 fn test_reputation_update_creates_entry() {
883 let mut manager = ReputationManager::new(0.1, 0.1);
884 let peer_id = "test_peer".to_string();
885
886 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
887
888 let reputation = manager.get_reputation(&peer_id);
889 assert!(reputation.is_some());
890
891 let rep = reputation.unwrap();
892 assert_eq!(rep.peer_id, peer_id);
893 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
895 }
896
897 #[test]
898 fn test_reputation_update_success_improves_rate() {
899 let mut manager = ReputationManager::new(0.1, 0.1);
900 let peer_id = "test_peer".to_string();
901
902 for _ in 0..15 {
904 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
905 }
906
907 let reputation = manager.get_reputation(&peer_id).unwrap();
908 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
910 }
911
912 #[test]
913 fn test_reputation_update_failure_decreases_rate() {
914 let mut manager = ReputationManager::new(0.1, 0.1);
915 let peer_id = "test_peer".to_string();
916
917 for _ in 0..15 {
919 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
920 }
921
922 let reputation = manager.get_reputation(&peer_id).unwrap();
923 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
925 }
926
927 #[test]
928 fn test_reputation_response_time_tracking() {
929 let mut manager = ReputationManager::new(0.1, 0.1);
930 let peer_id = "test_peer".to_string();
931
932 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
934
935 let reputation = manager.get_reputation(&peer_id).unwrap();
936 assert!(reputation.response_time.as_millis() > 200);
938 assert!(reputation.response_time.as_millis() < 500);
939 }
940
941 #[test]
942 fn test_reputation_decay() {
943 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
945
946 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
948
949 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
951 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
953
954 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
955
956 manager.apply_decay();
958
959 let reputation = manager.get_reputation(&peer_id);
960 if let Some(rep) = reputation {
961 assert!(rep.response_rate < original_rate);
963 } }
965
966 #[test]
967 fn test_reputation_decay_removes_low_reputation() {
968 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
970
971 for _ in 0..10 {
973 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
974 }
975
976 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
978 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
981
982 manager.apply_decay();
984
985 assert!(manager.get_reputation(&peer_id).is_none());
987 }
988
989 #[test]
990 fn test_security_types_keypair() {
991 let keypair = security_types::KeyPair::generate();
992
993 let public_key_bytes = keypair.public_key_bytes();
994 assert_eq!(public_key_bytes.len(), 32);
995
996 let message = b"test message";
997 let signature = keypair.sign(message);
998 assert_eq!(signature.len(), 64);
999
1000 let inner = keypair.inner();
1002 assert!(inner.verify(message, &Signature::from_bytes(&signature).unwrap()).is_ok());
1003 }
1004
1005 #[test]
1006 fn test_node_reputation_structure() {
1007 let peer_id = "test_peer".to_string();
1008 let reputation = NodeReputation {
1009 peer_id: peer_id.clone(),
1010 response_rate: 0.85,
1011 response_time: Duration::from_millis(150),
1012 consistency_score: 0.9,
1013 uptime_estimate: Duration::from_secs(86400),
1014 routing_accuracy: 0.8,
1015 last_seen: SystemTime::now(),
1016 interaction_count: 42,
1017 };
1018
1019 assert_eq!(reputation.peer_id, peer_id);
1020 assert_eq!(reputation.response_rate, 0.85);
1021 assert_eq!(reputation.response_time, Duration::from_millis(150));
1022 assert_eq!(reputation.consistency_score, 0.9);
1023 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1024 assert_eq!(reputation.routing_accuracy, 0.8);
1025 assert_eq!(reputation.interaction_count, 42);
1026 }
1027
1028 #[test]
1029 fn test_ip_analysis_structure() {
1030 let analysis = IPAnalysis {
1031 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1032 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1033 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1034 asn: Some(64512),
1035 country: Some("US".to_string()),
1036 is_hosting_provider: true,
1037 is_vpn_provider: false,
1038 reputation_score: 0.75,
1039 };
1040
1041 assert_eq!(analysis.asn, Some(64512));
1042 assert_eq!(analysis.country, Some("US".to_string()));
1043 assert!(analysis.is_hosting_provider);
1044 assert!(!analysis.is_vpn_provider);
1045 assert_eq!(analysis.reputation_score, 0.75);
1046 }
1047
1048 #[test]
1049 fn test_diversity_stats_structure() {
1050 let stats = DiversityStats {
1051 total_64_subnets: 100,
1052 total_48_subnets: 50,
1053 total_32_subnets: 25,
1054 total_asns: 15,
1055 total_countries: 8,
1056 max_nodes_per_64: 1,
1057 max_nodes_per_48: 3,
1058 max_nodes_per_32: 10,
1059 };
1060
1061 assert_eq!(stats.total_64_subnets, 100);
1062 assert_eq!(stats.total_48_subnets, 50);
1063 assert_eq!(stats.total_32_subnets, 25);
1064 assert_eq!(stats.total_asns, 15);
1065 assert_eq!(stats.total_countries, 8);
1066 assert_eq!(stats.max_nodes_per_64, 1);
1067 assert_eq!(stats.max_nodes_per_48, 3);
1068 assert_eq!(stats.max_nodes_per_32, 10);
1069 }
1070
1071 #[test]
1072 fn test_multiple_same_subnet_nodes() -> Result<()> {
1073 let config = IPDiversityConfig {
1074 max_nodes_per_64: 3, max_nodes_per_48: 5,
1076 max_nodes_per_32: 10,
1077 ..create_test_diversity_config()
1078 };
1079 let mut enforcer = IPDiversityEnforcer::new(config);
1080
1081 let _base_addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000);
1082
1083 for i in 1..=3 {
1085 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1086 let analysis = enforcer.analyze_ip(addr)?;
1087 assert!(enforcer.can_accept_node(&analysis));
1088 enforcer.add_node(&analysis)?;
1089 }
1090
1091 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1093 let analysis4 = enforcer.analyze_ip(addr4)?;
1094 assert!(!enforcer.can_accept_node(&analysis4));
1095
1096 let stats = enforcer.get_diversity_stats();
1097 assert_eq!(stats.total_64_subnets, 1);
1098 assert_eq!(stats.max_nodes_per_64, 3);
1099
1100 Ok(())
1101 }
1102
1103 #[test]
1104 fn test_asn_and_country_tracking() -> Result<()> {
1105 let config = create_test_diversity_config();
1106 let mut enforcer = IPDiversityEnforcer::new(config);
1107
1108 let ipv6_addr = create_test_ipv6();
1110 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1111 analysis.asn = Some(64512);
1112 analysis.country = Some("US".to_string());
1113
1114 enforcer.add_node(&analysis)?;
1115
1116 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1117 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1118
1119 enforcer.remove_node(&analysis);
1121 assert!(enforcer.asn_counts.get(&64512).is_none());
1122 assert!(enforcer.country_counts.get("US").is_none());
1123
1124 Ok(())
1125 }
1126
1127 #[test]
1128 fn test_reputation_mixed_interactions() {
1129 let mut manager = ReputationManager::new(0.1, 0.1);
1130 let peer_id = "test_peer".to_string();
1131
1132 for i in 0..15 {
1134 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1136 }
1137
1138 let reputation = manager.get_reputation(&peer_id).unwrap();
1139 assert!(reputation.response_rate > 0.55);
1142 assert!(reputation.response_rate < 0.85);
1143 assert_eq!(reputation.interaction_count, 15);
1144 }
1145}