1use crate::PeerId;
21use anyhow::{Result, anyhow};
22use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
23use rand::rngs::OsRng;
24use serde::{Deserialize, Serialize};
25use sha2::{Digest, Sha256};
26use std::collections::HashMap;
27use std::net::Ipv6Addr;
28use std::time::{Duration, SystemTime, UNIX_EPOCH};
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct IPv6NodeID {
33 pub node_id: Vec<u8>,
35 pub ipv6_addr: Ipv6Addr,
37 pub public_key: Vec<u8>,
39 pub signature: Vec<u8>,
41 pub timestamp_secs: u64,
43 pub salt: Vec<u8>,
45}
46
47#[derive(Debug, Clone)]
49pub struct IPDiversityConfig {
50 pub max_nodes_per_64: usize,
52 pub max_nodes_per_48: usize,
54 pub max_nodes_per_32: usize,
56 pub max_nodes_per_asn: usize,
58 pub enable_geolocation_check: bool,
60 pub min_geographic_diversity: usize,
62}
63
64#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
66pub struct IPAnalysis {
67 pub subnet_64: Ipv6Addr,
69 pub subnet_48: Ipv6Addr,
71 pub subnet_32: Ipv6Addr,
73 pub asn: Option<u32>,
75 pub country: Option<String>,
77 pub is_hosting_provider: bool,
79 pub is_vpn_provider: bool,
81 pub reputation_score: f64,
83}
84
85#[derive(Debug, Clone)]
87pub struct NodeReputation {
88 pub peer_id: PeerId,
90 pub response_rate: f64,
92 pub response_time: Duration,
94 pub consistency_score: f64,
96 pub uptime_estimate: Duration,
98 pub routing_accuracy: f64,
100 pub last_seen: SystemTime,
102 pub interaction_count: u64,
104}
105
106impl Default for IPDiversityConfig {
107 fn default() -> Self {
108 Self {
109 max_nodes_per_64: 1,
110 max_nodes_per_48: 3,
111 max_nodes_per_32: 10,
112 max_nodes_per_asn: 20,
113 enable_geolocation_check: true,
114 min_geographic_diversity: 3,
115 }
116 }
117}
118
119impl IPv6NodeID {
120 pub fn generate(ipv6_addr: Ipv6Addr, keypair: &SigningKey) -> Result<Self> {
122 let mut rng = rand::thread_rng();
123 let mut salt = vec![0u8; 16];
124 rand::RngCore::fill_bytes(&mut rng, &mut salt);
125
126 let timestamp = SystemTime::now();
127 let timestamp_secs = timestamp.duration_since(UNIX_EPOCH)?.as_secs();
128 let public_key = keypair.verifying_key().to_bytes().to_vec();
129
130 let mut hasher = Sha256::new();
132 hasher.update(ipv6_addr.octets());
133 hasher.update(&public_key);
134 hasher.update(&salt);
135 hasher.update(timestamp_secs.to_le_bytes());
136 let node_id = hasher.finalize().to_vec();
137
138 let mut message_to_sign = Vec::new();
140 message_to_sign.extend_from_slice(&ipv6_addr.octets());
141 message_to_sign.extend_from_slice(&public_key);
142 message_to_sign.extend_from_slice(&salt);
143 message_to_sign.extend_from_slice(×tamp_secs.to_le_bytes());
144
145 let signature = keypair.sign(&message_to_sign).to_bytes().to_vec();
146
147 Ok(IPv6NodeID {
148 node_id,
149 ipv6_addr,
150 public_key,
151 signature,
152 timestamp_secs,
153 salt,
154 })
155 }
156
157 pub fn verify(&self) -> Result<bool> {
159 let mut hasher = Sha256::new();
161 hasher.update(self.ipv6_addr.octets());
162 hasher.update(&self.public_key);
163 hasher.update(&self.salt);
164 hasher.update(self.timestamp_secs.to_le_bytes());
165 let expected_node_id = hasher.finalize();
166
167 if expected_node_id.as_slice() != self.node_id {
169 return Ok(false);
170 }
171
172 if self.public_key.len() != 32 {
174 return Ok(false);
175 }
176 if self.signature.len() != 64 {
177 return Ok(false);
178 }
179
180 let mut pk_bytes = [0u8; 32];
181 pk_bytes.copy_from_slice(&self.public_key);
182 let public_key = VerifyingKey::from_bytes(&pk_bytes)
183 .map_err(|e| anyhow!("Invalid public key: {}", e))?;
184
185 let mut sig_bytes = [0u8; 64];
186 sig_bytes.copy_from_slice(&self.signature);
187 let signature = Signature::from_bytes(&sig_bytes);
188
189 let mut message_to_verify = Vec::new();
190 message_to_verify.extend_from_slice(&self.ipv6_addr.octets());
191 message_to_verify.extend_from_slice(&self.public_key);
192 message_to_verify.extend_from_slice(&self.salt);
193 message_to_verify.extend_from_slice(&self.timestamp_secs.to_le_bytes());
194
195 match public_key.verify(&message_to_verify, &signature) {
196 Ok(_) => Ok(true),
197 Err(_) => Ok(false),
198 }
199 }
200
201 pub fn extract_subnet_64(&self) -> Ipv6Addr {
203 let octets = self.ipv6_addr.octets();
204 let mut subnet = [0u8; 16];
205 subnet[..8].copy_from_slice(&octets[..8]); Ipv6Addr::from(subnet)
207 }
208
209 pub fn extract_subnet_48(&self) -> Ipv6Addr {
211 let octets = self.ipv6_addr.octets();
212 let mut subnet = [0u8; 16];
213 subnet[..6].copy_from_slice(&octets[..6]); Ipv6Addr::from(subnet)
215 }
216
217 pub fn extract_subnet_32(&self) -> Ipv6Addr {
219 let octets = self.ipv6_addr.octets();
220 let mut subnet = [0u8; 16];
221 subnet[..4].copy_from_slice(&octets[..4]); Ipv6Addr::from(subnet)
223 }
224}
225
226#[derive(Debug)]
228pub struct IPDiversityEnforcer {
229 config: IPDiversityConfig,
230 subnet_64_counts: HashMap<Ipv6Addr, usize>,
231 subnet_48_counts: HashMap<Ipv6Addr, usize>,
232 subnet_32_counts: HashMap<Ipv6Addr, usize>,
233 asn_counts: HashMap<u32, usize>,
234 country_counts: HashMap<String, usize>,
235}
236
237impl IPDiversityEnforcer {
238 pub fn new(config: IPDiversityConfig) -> Self {
240 Self {
241 config,
242 subnet_64_counts: HashMap::new(),
243 subnet_48_counts: HashMap::new(),
244 subnet_32_counts: HashMap::new(),
245 asn_counts: HashMap::new(),
246 country_counts: HashMap::new(),
247 }
248 }
249
250 pub fn analyze_ip(&self, ipv6_addr: Ipv6Addr) -> Result<IPAnalysis> {
252 let subnet_64 = Self::extract_subnet_prefix(ipv6_addr, 64);
253 let subnet_48 = Self::extract_subnet_prefix(ipv6_addr, 48);
254 let subnet_32 = Self::extract_subnet_prefix(ipv6_addr, 32);
255
256 let asn = None;
258
259 let country = None;
261
262 let is_hosting_provider = false;
264 let is_vpn_provider = false;
265
266 let reputation_score = 0.5;
268
269 Ok(IPAnalysis {
270 subnet_64,
271 subnet_48,
272 subnet_32,
273 asn,
274 country,
275 is_hosting_provider,
276 is_vpn_provider,
277 reputation_score,
278 })
279 }
280
281 pub fn can_accept_node(&self, ip_analysis: &IPAnalysis) -> bool {
283 let (limit_64, limit_48, limit_32, limit_asn) =
285 if ip_analysis.is_hosting_provider || ip_analysis.is_vpn_provider {
286 (
288 std::cmp::max(1, self.config.max_nodes_per_64 / 2),
289 std::cmp::max(1, self.config.max_nodes_per_48 / 2),
290 std::cmp::max(1, self.config.max_nodes_per_32 / 2),
291 std::cmp::max(1, self.config.max_nodes_per_asn / 2),
292 )
293 } else {
294 (
296 self.config.max_nodes_per_64,
297 self.config.max_nodes_per_48,
298 self.config.max_nodes_per_32,
299 self.config.max_nodes_per_asn,
300 )
301 };
302
303 if let Some(&count) = self.subnet_64_counts.get(&ip_analysis.subnet_64)
305 && count >= limit_64
306 {
307 return false;
308 }
309
310 if let Some(&count) = self.subnet_48_counts.get(&ip_analysis.subnet_48)
312 && count >= limit_48
313 {
314 return false;
315 }
316
317 if let Some(&count) = self.subnet_32_counts.get(&ip_analysis.subnet_32)
319 && count >= limit_32
320 {
321 return false;
322 }
323
324 if let Some(asn) = ip_analysis.asn
326 && let Some(&count) = self.asn_counts.get(&asn)
327 && count >= limit_asn
328 {
329 return false;
330 }
331
332 true
333 }
334
335 pub fn add_node(&mut self, ip_analysis: &IPAnalysis) -> Result<()> {
337 if !self.can_accept_node(ip_analysis) {
338 return Err(anyhow!("IP diversity limits exceeded"));
339 }
340
341 *self
343 .subnet_64_counts
344 .entry(ip_analysis.subnet_64)
345 .or_insert(0) += 1;
346 *self
347 .subnet_48_counts
348 .entry(ip_analysis.subnet_48)
349 .or_insert(0) += 1;
350 *self
351 .subnet_32_counts
352 .entry(ip_analysis.subnet_32)
353 .or_insert(0) += 1;
354
355 if let Some(asn) = ip_analysis.asn {
356 *self.asn_counts.entry(asn).or_insert(0) += 1;
357 }
358
359 if let Some(ref country) = ip_analysis.country {
360 *self.country_counts.entry(country.clone()).or_insert(0) += 1;
361 }
362
363 Ok(())
364 }
365
366 pub fn remove_node(&mut self, ip_analysis: &IPAnalysis) {
368 if let Some(count) = self.subnet_64_counts.get_mut(&ip_analysis.subnet_64) {
369 *count = count.saturating_sub(1);
370 if *count == 0 {
371 self.subnet_64_counts.remove(&ip_analysis.subnet_64);
372 }
373 }
374
375 if let Some(count) = self.subnet_48_counts.get_mut(&ip_analysis.subnet_48) {
376 *count = count.saturating_sub(1);
377 if *count == 0 {
378 self.subnet_48_counts.remove(&ip_analysis.subnet_48);
379 }
380 }
381
382 if let Some(count) = self.subnet_32_counts.get_mut(&ip_analysis.subnet_32) {
383 *count = count.saturating_sub(1);
384 if *count == 0 {
385 self.subnet_32_counts.remove(&ip_analysis.subnet_32);
386 }
387 }
388
389 if let Some(asn) = ip_analysis.asn
390 && let Some(count) = self.asn_counts.get_mut(&asn)
391 {
392 *count = count.saturating_sub(1);
393 if *count == 0 {
394 self.asn_counts.remove(&asn);
395 }
396 }
397
398 if let Some(ref country) = ip_analysis.country
399 && let Some(count) = self.country_counts.get_mut(country)
400 {
401 *count = count.saturating_sub(1);
402 if *count == 0 {
403 self.country_counts.remove(country);
404 }
405 }
406 }
407
408 pub fn extract_subnet_prefix(addr: Ipv6Addr, prefix_len: u8) -> Ipv6Addr {
410 let octets = addr.octets();
411 let mut subnet = [0u8; 16];
412
413 let bytes_to_copy = (prefix_len / 8) as usize;
414 let remaining_bits = prefix_len % 8;
415
416 if bytes_to_copy < 16 {
418 subnet[..bytes_to_copy].copy_from_slice(&octets[..bytes_to_copy]);
419 } else {
420 subnet.copy_from_slice(&octets);
421 }
422
423 if remaining_bits > 0 && bytes_to_copy < 16 {
425 let mask = 0xFF << (8 - remaining_bits);
426 subnet[bytes_to_copy] = octets[bytes_to_copy] & mask;
427 }
428
429 Ipv6Addr::from(subnet)
430 }
431
432 pub fn get_diversity_stats(&self) -> DiversityStats {
434 DiversityStats {
435 total_64_subnets: self.subnet_64_counts.len(),
436 total_48_subnets: self.subnet_48_counts.len(),
437 total_32_subnets: self.subnet_32_counts.len(),
438 total_asns: self.asn_counts.len(),
439 total_countries: self.country_counts.len(),
440 max_nodes_per_64: self.subnet_64_counts.values().max().copied().unwrap_or(0),
441 max_nodes_per_48: self.subnet_48_counts.values().max().copied().unwrap_or(0),
442 max_nodes_per_32: self.subnet_32_counts.values().max().copied().unwrap_or(0),
443 }
444 }
445}
446
447#[derive(Debug, Clone, Serialize, Deserialize)]
449pub struct DiversityStats {
450 pub total_64_subnets: usize,
452 pub total_48_subnets: usize,
454 pub total_32_subnets: usize,
456 pub total_asns: usize,
458 pub total_countries: usize,
460 pub max_nodes_per_64: usize,
462 pub max_nodes_per_48: usize,
464 pub max_nodes_per_32: usize,
466}
467
468#[derive(Debug)]
470pub struct ReputationManager {
471 reputations: HashMap<PeerId, NodeReputation>,
472 reputation_decay: f64,
473 min_reputation: f64,
474}
475
476impl ReputationManager {
477 pub fn new(reputation_decay: f64, min_reputation: f64) -> Self {
479 Self {
480 reputations: HashMap::new(),
481 reputation_decay,
482 min_reputation,
483 }
484 }
485
486 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<&NodeReputation> {
488 self.reputations.get(peer_id)
489 }
490
491 pub fn update_reputation(&mut self, peer_id: &PeerId, success: bool, response_time: Duration) {
493 let reputation =
494 self.reputations
495 .entry(peer_id.clone())
496 .or_insert_with(|| NodeReputation {
497 peer_id: peer_id.clone(),
498 response_rate: 0.5,
499 response_time: Duration::from_millis(500),
500 consistency_score: 0.5,
501 uptime_estimate: Duration::from_secs(0),
502 routing_accuracy: 0.5,
503 last_seen: SystemTime::now(),
504 interaction_count: 0,
505 });
506
507 let alpha = 0.3; if success {
511 reputation.response_rate = reputation.response_rate * (1.0 - alpha) + alpha;
512 } else {
513 reputation.response_rate *= 1.0 - alpha;
514 }
515
516 let response_time_ms = response_time.as_millis() as f64;
518 let current_response_ms = reputation.response_time.as_millis() as f64;
519 let new_response_ms = current_response_ms * (1.0 - alpha) + response_time_ms * alpha;
520 reputation.response_time = Duration::from_millis(new_response_ms as u64);
521
522 reputation.last_seen = SystemTime::now();
523 reputation.interaction_count += 1;
524 }
525
526 pub fn apply_decay(&mut self) {
528 let now = SystemTime::now();
529
530 self.reputations.retain(|_, reputation| {
531 if let Ok(elapsed) = now.duration_since(reputation.last_seen) {
532 let decay_factor = (-elapsed.as_secs_f64() / 3600.0 * self.reputation_decay).exp();
534 reputation.response_rate *= decay_factor;
535 reputation.consistency_score *= decay_factor;
536 reputation.routing_accuracy *= decay_factor;
537
538 reputation.response_rate > self.min_reputation / 10.0
540 } else {
541 true
542 }
543 });
544 }
545}
546
547pub mod security_types {
549 use super::*;
550
551 pub struct KeyPair {
553 inner: SigningKey,
554 }
555
556 impl KeyPair {
557 pub fn generate() -> Self {
559 let signing_key = SigningKey::generate(&mut OsRng);
561
562 KeyPair { inner: signing_key }
563 }
564
565 pub fn inner(&self) -> &SigningKey {
567 &self.inner
568 }
569
570 pub fn public_key_bytes(&self) -> [u8; 32] {
572 self.inner.verifying_key().to_bytes()
573 }
574
575 pub fn sign(&self, message: &[u8]) -> [u8; 64] {
577 self.inner.sign(message).to_bytes()
578 }
579 }
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585
586 fn create_test_keypair() -> SigningKey {
587 let mut csprng = rand::rngs::OsRng;
588 SigningKey::generate(&mut csprng)
589 }
590
591 fn create_test_ipv6() -> Ipv6Addr {
592 Ipv6Addr::new(
593 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334,
594 )
595 }
596
597 fn create_test_diversity_config() -> IPDiversityConfig {
598 IPDiversityConfig {
599 max_nodes_per_64: 1,
600 max_nodes_per_48: 3,
601 max_nodes_per_32: 10,
602 max_nodes_per_asn: 20,
603 enable_geolocation_check: true,
604 min_geographic_diversity: 3,
605 }
606 }
607
608 #[test]
609 fn test_ipv6_node_id_generation() -> Result<()> {
610 let keypair = create_test_keypair();
611 let ipv6_addr = create_test_ipv6();
612
613 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
614
615 assert_eq!(node_id.ipv6_addr, ipv6_addr);
616 assert_eq!(node_id.public_key.len(), 32);
617 assert_eq!(node_id.signature.len(), 64);
618 assert_eq!(node_id.node_id.len(), 32); assert_eq!(node_id.salt.len(), 16);
620 assert!(node_id.timestamp_secs > 0);
621
622 Ok(())
623 }
624
625 #[test]
626 fn test_ipv6_node_id_verification() -> Result<()> {
627 let keypair = create_test_keypair();
628 let ipv6_addr = create_test_ipv6();
629
630 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
631 let is_valid = node_id.verify()?;
632
633 assert!(is_valid);
634
635 Ok(())
636 }
637
638 #[test]
639 fn test_ipv6_node_id_verification_fails_with_wrong_data() -> Result<()> {
640 let keypair = create_test_keypair();
641 let ipv6_addr = create_test_ipv6();
642
643 let mut node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
644
645 node_id.node_id[0] ^= 0xFF;
647 let is_valid = node_id.verify()?;
648 assert!(!is_valid);
649
650 let mut node_id2 = IPv6NodeID::generate(ipv6_addr, &keypair)?;
652 node_id2.signature = vec![0u8; 32]; let is_valid2 = node_id2.verify()?;
654 assert!(!is_valid2);
655
656 let mut node_id3 = IPv6NodeID::generate(ipv6_addr, &keypair)?;
658 node_id3.public_key = vec![0u8; 16]; let is_valid3 = node_id3.verify()?;
660 assert!(!is_valid3);
661
662 Ok(())
663 }
664
665 #[test]
666 fn test_ipv6_subnet_extraction() -> Result<()> {
667 let keypair = create_test_keypair();
668 let ipv6_addr = Ipv6Addr::new(
669 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
670 );
671
672 let node_id = IPv6NodeID::generate(ipv6_addr, &keypair)?;
673
674 let subnet_64 = node_id.extract_subnet_64();
676 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
677 assert_eq!(subnet_64, expected_64);
678
679 let subnet_48 = node_id.extract_subnet_48();
681 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
682 assert_eq!(subnet_48, expected_48);
683
684 let subnet_32 = node_id.extract_subnet_32();
686 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
687 assert_eq!(subnet_32, expected_32);
688
689 Ok(())
690 }
691
692 #[test]
693 fn test_ip_diversity_config_default() {
694 let config = IPDiversityConfig::default();
695
696 assert_eq!(config.max_nodes_per_64, 1);
697 assert_eq!(config.max_nodes_per_48, 3);
698 assert_eq!(config.max_nodes_per_32, 10);
699 assert_eq!(config.max_nodes_per_asn, 20);
700 assert!(config.enable_geolocation_check);
701 assert_eq!(config.min_geographic_diversity, 3);
702 }
703
704 #[test]
705 fn test_ip_diversity_enforcer_creation() {
706 let config = create_test_diversity_config();
707 let enforcer = IPDiversityEnforcer::new(config.clone());
708
709 assert_eq!(enforcer.config.max_nodes_per_64, config.max_nodes_per_64);
710 assert_eq!(enforcer.subnet_64_counts.len(), 0);
711 assert_eq!(enforcer.subnet_48_counts.len(), 0);
712 assert_eq!(enforcer.subnet_32_counts.len(), 0);
713 }
714
715 #[test]
716 fn test_ip_analysis() -> Result<()> {
717 let config = create_test_diversity_config();
718 let enforcer = IPDiversityEnforcer::new(config);
719
720 let ipv6_addr = create_test_ipv6();
721 let analysis = enforcer.analyze_ip(ipv6_addr)?;
722
723 assert_eq!(
724 analysis.subnet_64,
725 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 64)
726 );
727 assert_eq!(
728 analysis.subnet_48,
729 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 48)
730 );
731 assert_eq!(
732 analysis.subnet_32,
733 IPDiversityEnforcer::extract_subnet_prefix(ipv6_addr, 32)
734 );
735 assert!(analysis.asn.is_none()); assert!(analysis.country.is_none()); assert!(!analysis.is_hosting_provider);
738 assert!(!analysis.is_vpn_provider);
739 assert_eq!(analysis.reputation_score, 0.5);
740
741 Ok(())
742 }
743
744 #[test]
745 fn test_can_accept_node_basic() -> Result<()> {
746 let config = create_test_diversity_config();
747 let enforcer = IPDiversityEnforcer::new(config);
748
749 let ipv6_addr = create_test_ipv6();
750 let analysis = enforcer.analyze_ip(ipv6_addr)?;
751
752 assert!(enforcer.can_accept_node(&analysis));
754
755 Ok(())
756 }
757
758 #[test]
759 fn test_add_and_remove_node() -> Result<()> {
760 let config = create_test_diversity_config();
761 let mut enforcer = IPDiversityEnforcer::new(config);
762
763 let ipv6_addr = create_test_ipv6();
764 let analysis = enforcer.analyze_ip(ipv6_addr)?;
765
766 enforcer.add_node(&analysis)?;
768 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), Some(&1));
769 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), Some(&1));
770 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), Some(&1));
771
772 enforcer.remove_node(&analysis);
774 assert_eq!(enforcer.subnet_64_counts.get(&analysis.subnet_64), None);
775 assert_eq!(enforcer.subnet_48_counts.get(&analysis.subnet_48), None);
776 assert_eq!(enforcer.subnet_32_counts.get(&analysis.subnet_32), None);
777
778 Ok(())
779 }
780
781 #[test]
782 fn test_diversity_limits_enforcement() -> Result<()> {
783 let config = create_test_diversity_config();
784 let mut enforcer = IPDiversityEnforcer::new(config);
785
786 let ipv6_addr1 = Ipv6Addr::new(
787 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
788 );
789 let ipv6_addr2 = Ipv6Addr::new(
790 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7335,
791 ); let analysis1 = enforcer.analyze_ip(ipv6_addr1)?;
794 let analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
795
796 assert!(enforcer.can_accept_node(&analysis1));
798 enforcer.add_node(&analysis1)?;
799
800 assert!(!enforcer.can_accept_node(&analysis2));
802
803 let result = enforcer.add_node(&analysis2);
805 assert!(result.is_err());
806 assert!(
807 result
808 .unwrap_err()
809 .to_string()
810 .contains("IP diversity limits exceeded")
811 );
812
813 Ok(())
814 }
815
816 #[test]
817 fn test_hosting_provider_stricter_limits() -> Result<()> {
818 let config = IPDiversityConfig {
819 max_nodes_per_64: 4, max_nodes_per_48: 8,
821 ..create_test_diversity_config()
822 };
823 let mut enforcer = IPDiversityEnforcer::new(config);
824
825 let ipv6_addr = create_test_ipv6();
826 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
827 analysis.is_hosting_provider = true;
828
829 assert!(enforcer.can_accept_node(&analysis));
831 enforcer.add_node(&analysis)?;
832
833 let ipv6_addr2 = Ipv6Addr::new(
835 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7335,
836 );
837 let mut analysis2 = enforcer.analyze_ip(ipv6_addr2)?;
838 analysis2.is_hosting_provider = true;
839 analysis2.subnet_64 = analysis.subnet_64; assert!(enforcer.can_accept_node(&analysis2));
842 enforcer.add_node(&analysis2)?;
843
844 let ipv6_addr3 = Ipv6Addr::new(
846 0x2001, 0xdb8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7336,
847 );
848 let mut analysis3 = enforcer.analyze_ip(ipv6_addr3)?;
849 analysis3.is_hosting_provider = true;
850 analysis3.subnet_64 = analysis.subnet_64; assert!(!enforcer.can_accept_node(&analysis3));
853
854 Ok(())
855 }
856
857 #[test]
858 fn test_diversity_stats() -> Result<()> {
859 let config = create_test_diversity_config();
860 let mut enforcer = IPDiversityEnforcer::new(config);
861
862 let addresses = [
864 Ipv6Addr::new(
865 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
866 ),
867 Ipv6Addr::new(
868 0x2001, 0xdb8, 0x85a4, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
869 ), Ipv6Addr::new(
871 0x2002, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
872 ), ];
874
875 for addr in addresses {
876 let analysis = enforcer.analyze_ip(addr)?;
877 enforcer.add_node(&analysis)?;
878 }
879
880 let stats = enforcer.get_diversity_stats();
881 assert_eq!(stats.total_64_subnets, 3);
882 assert_eq!(stats.total_48_subnets, 3);
883 assert_eq!(stats.total_32_subnets, 2); assert_eq!(stats.max_nodes_per_64, 1);
885 assert_eq!(stats.max_nodes_per_48, 1);
886 assert_eq!(stats.max_nodes_per_32, 2); Ok(())
889 }
890
891 #[test]
892 fn test_extract_subnet_prefix() {
893 let addr = Ipv6Addr::new(
894 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x7334,
895 );
896
897 let prefix_64 = IPDiversityEnforcer::extract_subnet_prefix(addr, 64);
899 let expected_64 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0);
900 assert_eq!(prefix_64, expected_64);
901
902 let prefix_48 = IPDiversityEnforcer::extract_subnet_prefix(addr, 48);
904 let expected_48 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0);
905 assert_eq!(prefix_48, expected_48);
906
907 let prefix_32 = IPDiversityEnforcer::extract_subnet_prefix(addr, 32);
909 let expected_32 = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
910 assert_eq!(prefix_32, expected_32);
911
912 let prefix_56 = IPDiversityEnforcer::extract_subnet_prefix(addr, 56);
914 let expected_56 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1200, 0, 0, 0, 0);
915 assert_eq!(prefix_56, expected_56);
916
917 let prefix_128 = IPDiversityEnforcer::extract_subnet_prefix(addr, 128);
919 assert_eq!(prefix_128, addr);
920 }
921
922 #[test]
923 fn test_reputation_manager_creation() {
924 let manager = ReputationManager::new(0.1, 0.1);
925 assert_eq!(manager.reputation_decay, 0.1);
926 assert_eq!(manager.min_reputation, 0.1);
927 assert_eq!(manager.reputations.len(), 0);
928 }
929
930 #[test]
931 fn test_reputation_get_nonexistent() {
932 let manager = ReputationManager::new(0.1, 0.1);
933 let peer_id = "test_peer".to_string();
934
935 let reputation = manager.get_reputation(&peer_id);
936 assert!(reputation.is_none());
937 }
938
939 #[test]
940 fn test_reputation_update_creates_entry() {
941 let mut manager = ReputationManager::new(0.1, 0.1);
942 let peer_id = "test_peer".to_string();
943
944 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
945
946 let reputation = manager.get_reputation(&peer_id);
947 assert!(reputation.is_some());
948
949 let rep = reputation.unwrap();
950 assert_eq!(rep.peer_id, peer_id);
951 assert!(rep.response_rate > 0.5); assert_eq!(rep.interaction_count, 1);
953 }
954
955 #[test]
956 fn test_reputation_update_success_improves_rate() {
957 let mut manager = ReputationManager::new(0.1, 0.1);
958 let peer_id = "test_peer".to_string();
959
960 for _ in 0..15 {
962 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
963 }
964
965 let reputation = manager.get_reputation(&peer_id).unwrap();
966 assert!(reputation.response_rate > 0.85); assert_eq!(reputation.interaction_count, 15);
968 }
969
970 #[test]
971 fn test_reputation_update_failure_decreases_rate() {
972 let mut manager = ReputationManager::new(0.1, 0.1);
973 let peer_id = "test_peer".to_string();
974
975 for _ in 0..15 {
977 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
978 }
979
980 let reputation = manager.get_reputation(&peer_id).unwrap();
981 assert!(reputation.response_rate < 0.15); assert_eq!(reputation.interaction_count, 15);
983 }
984
985 #[test]
986 fn test_reputation_response_time_tracking() {
987 let mut manager = ReputationManager::new(0.1, 0.1);
988 let peer_id = "test_peer".to_string();
989
990 manager.update_reputation(&peer_id, true, Duration::from_millis(200));
992
993 let reputation = manager.get_reputation(&peer_id).unwrap();
994 assert!(reputation.response_time.as_millis() > 200);
996 assert!(reputation.response_time.as_millis() < 500);
997 }
998
999 #[test]
1000 fn test_reputation_decay() {
1001 let mut manager = ReputationManager::new(1.0, 0.01); let peer_id = "test_peer".to_string();
1003
1004 manager.update_reputation(&peer_id, true, Duration::from_millis(100));
1006
1007 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1009 reputation.last_seen = SystemTime::now() - Duration::from_secs(7200); }
1011
1012 let original_rate = manager.get_reputation(&peer_id).unwrap().response_rate;
1013
1014 manager.apply_decay();
1016
1017 let reputation = manager.get_reputation(&peer_id);
1018 if let Some(rep) = reputation {
1019 assert!(rep.response_rate < original_rate);
1021 } }
1023
1024 #[test]
1025 fn test_reputation_decay_removes_low_reputation() {
1026 let mut manager = ReputationManager::new(0.1, 0.5); let peer_id = "test_peer".to_string();
1028
1029 for _ in 0..10 {
1031 manager.update_reputation(&peer_id, false, Duration::from_millis(1000));
1032 }
1033
1034 if let Some(reputation) = manager.reputations.get_mut(&peer_id) {
1036 reputation.last_seen = SystemTime::now() - Duration::from_secs(3600); reputation.response_rate = 0.01; }
1039
1040 manager.apply_decay();
1042
1043 assert!(manager.get_reputation(&peer_id).is_none());
1045 }
1046
1047 #[test]
1048 fn test_security_types_keypair() {
1049 let keypair = security_types::KeyPair::generate();
1050
1051 let public_key_bytes = keypair.public_key_bytes();
1052 assert_eq!(public_key_bytes.len(), 32);
1053
1054 let message = b"test message";
1055 let signature = keypair.sign(message);
1056 assert_eq!(signature.len(), 64);
1057
1058 let inner = keypair.inner();
1060 assert!(
1061 inner
1062 .verify(message, &Signature::from_bytes(&signature))
1063 .is_ok()
1064 );
1065 }
1066
1067 #[test]
1068 fn test_node_reputation_structure() {
1069 let peer_id = "test_peer".to_string();
1070 let reputation = NodeReputation {
1071 peer_id: peer_id.clone(),
1072 response_rate: 0.85,
1073 response_time: Duration::from_millis(150),
1074 consistency_score: 0.9,
1075 uptime_estimate: Duration::from_secs(86400),
1076 routing_accuracy: 0.8,
1077 last_seen: SystemTime::now(),
1078 interaction_count: 42,
1079 };
1080
1081 assert_eq!(reputation.peer_id, peer_id);
1082 assert_eq!(reputation.response_rate, 0.85);
1083 assert_eq!(reputation.response_time, Duration::from_millis(150));
1084 assert_eq!(reputation.consistency_score, 0.9);
1085 assert_eq!(reputation.uptime_estimate, Duration::from_secs(86400));
1086 assert_eq!(reputation.routing_accuracy, 0.8);
1087 assert_eq!(reputation.interaction_count, 42);
1088 }
1089
1090 #[test]
1091 fn test_ip_analysis_structure() {
1092 let analysis = IPAnalysis {
1093 subnet_64: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0, 0, 0, 0),
1094 subnet_48: Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0, 0, 0, 0, 0),
1095 subnet_32: Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
1096 asn: Some(64512),
1097 country: Some("US".to_string()),
1098 is_hosting_provider: true,
1099 is_vpn_provider: false,
1100 reputation_score: 0.75,
1101 };
1102
1103 assert_eq!(analysis.asn, Some(64512));
1104 assert_eq!(analysis.country, Some("US".to_string()));
1105 assert!(analysis.is_hosting_provider);
1106 assert!(!analysis.is_vpn_provider);
1107 assert_eq!(analysis.reputation_score, 0.75);
1108 }
1109
1110 #[test]
1111 fn test_diversity_stats_structure() {
1112 let stats = DiversityStats {
1113 total_64_subnets: 100,
1114 total_48_subnets: 50,
1115 total_32_subnets: 25,
1116 total_asns: 15,
1117 total_countries: 8,
1118 max_nodes_per_64: 1,
1119 max_nodes_per_48: 3,
1120 max_nodes_per_32: 10,
1121 };
1122
1123 assert_eq!(stats.total_64_subnets, 100);
1124 assert_eq!(stats.total_48_subnets, 50);
1125 assert_eq!(stats.total_32_subnets, 25);
1126 assert_eq!(stats.total_asns, 15);
1127 assert_eq!(stats.total_countries, 8);
1128 assert_eq!(stats.max_nodes_per_64, 1);
1129 assert_eq!(stats.max_nodes_per_48, 3);
1130 assert_eq!(stats.max_nodes_per_32, 10);
1131 }
1132
1133 #[test]
1134 fn test_multiple_same_subnet_nodes() -> Result<()> {
1135 let config = IPDiversityConfig {
1136 max_nodes_per_64: 3, max_nodes_per_48: 5,
1138 max_nodes_per_32: 10,
1139 ..create_test_diversity_config()
1140 };
1141 let mut enforcer = IPDiversityEnforcer::new(config);
1142
1143 let _base_addr = Ipv6Addr::new(
1144 0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 0x0000,
1145 );
1146
1147 for i in 1..=3 {
1149 let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, i);
1150 let analysis = enforcer.analyze_ip(addr)?;
1151 assert!(enforcer.can_accept_node(&analysis));
1152 enforcer.add_node(&analysis)?;
1153 }
1154
1155 let addr4 = Ipv6Addr::new(0x2001, 0xdb8, 0x85a3, 0x1234, 0x5678, 0x8a2e, 0x0370, 4);
1157 let analysis4 = enforcer.analyze_ip(addr4)?;
1158 assert!(!enforcer.can_accept_node(&analysis4));
1159
1160 let stats = enforcer.get_diversity_stats();
1161 assert_eq!(stats.total_64_subnets, 1);
1162 assert_eq!(stats.max_nodes_per_64, 3);
1163
1164 Ok(())
1165 }
1166
1167 #[test]
1168 fn test_asn_and_country_tracking() -> Result<()> {
1169 let config = create_test_diversity_config();
1170 let mut enforcer = IPDiversityEnforcer::new(config);
1171
1172 let ipv6_addr = create_test_ipv6();
1174 let mut analysis = enforcer.analyze_ip(ipv6_addr)?;
1175 analysis.asn = Some(64512);
1176 analysis.country = Some("US".to_string());
1177
1178 enforcer.add_node(&analysis)?;
1179
1180 assert_eq!(enforcer.asn_counts.get(&64512), Some(&1));
1181 assert_eq!(enforcer.country_counts.get("US"), Some(&1));
1182
1183 enforcer.remove_node(&analysis);
1185 assert!(enforcer.asn_counts.get(&64512).is_none());
1186 assert!(enforcer.country_counts.get("US").is_none());
1187
1188 Ok(())
1189 }
1190
1191 #[test]
1192 fn test_reputation_mixed_interactions() {
1193 let mut manager = ReputationManager::new(0.1, 0.1);
1194 let peer_id = "test_peer".to_string();
1195
1196 for i in 0..15 {
1198 let success = i % 3 != 0; manager.update_reputation(&peer_id, success, Duration::from_millis(100 + i * 10));
1200 }
1201
1202 let reputation = manager.get_reputation(&peer_id).unwrap();
1203 assert!(reputation.response_rate > 0.55);
1206 assert!(reputation.response_rate < 0.85);
1207 assert_eq!(reputation.interaction_count, 15);
1208 }
1209}