1use dashmap::DashMap;
39use libp2p::PeerId;
40use serde::{Deserialize, Serialize};
41use std::time::{Duration, Instant};
42
43#[derive(Debug, Clone)]
45pub struct ReputationConfig {
46 pub trust_threshold: f64,
48
49 pub bad_peer_threshold: f64,
51
52 pub transfer_success_weight: f64,
54
55 pub latency_weight: f64,
57
58 pub protocol_compliance_weight: f64,
60
61 pub uptime_weight: f64,
63
64 pub max_tracked_peers: usize,
66
67 pub retention_period: Duration,
69
70 pub score_decay_rate: f64,
72
73 pub ema_alpha: f64,
75}
76
77impl Default for ReputationConfig {
78 fn default() -> Self {
79 Self {
80 trust_threshold: 0.7,
81 bad_peer_threshold: 0.3,
82 transfer_success_weight: 0.4,
83 latency_weight: 0.2,
84 protocol_compliance_weight: 0.2,
85 uptime_weight: 0.2,
86 max_tracked_peers: 10000,
87 retention_period: Duration::from_secs(24 * 3600), score_decay_rate: 0.1,
89 ema_alpha: 0.3,
90 }
91 }
92}
93
94impl ReputationConfig {
95 pub fn strict() -> Self {
97 Self {
98 trust_threshold: 0.85,
99 bad_peer_threshold: 0.4,
100 transfer_success_weight: 0.5,
101 latency_weight: 0.2,
102 protocol_compliance_weight: 0.2,
103 uptime_weight: 0.1,
104 ema_alpha: 0.4,
105 ..Default::default()
106 }
107 }
108
109 pub fn lenient() -> Self {
111 Self {
112 trust_threshold: 0.5,
113 bad_peer_threshold: 0.2,
114 transfer_success_weight: 0.3,
115 latency_weight: 0.2,
116 protocol_compliance_weight: 0.1,
117 uptime_weight: 0.4,
118 ema_alpha: 0.2,
119 ..Default::default()
120 }
121 }
122
123 pub fn performance_focused() -> Self {
125 Self {
126 trust_threshold: 0.75,
127 bad_peer_threshold: 0.35,
128 transfer_success_weight: 0.3,
129 latency_weight: 0.5,
130 protocol_compliance_weight: 0.1,
131 uptime_weight: 0.1,
132 ema_alpha: 0.35,
133 ..Default::default()
134 }
135 }
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct ReputationScore {
141 pub transfer_success_rate: f64,
143
144 pub latency_score: f64,
146
147 pub protocol_compliance_score: f64,
149
150 pub uptime_score: f64,
152
153 pub successful_transfers: u64,
155
156 pub failed_transfers: u64,
158
159 pub protocol_violations: u64,
161
162 pub average_latency_ms: u64,
164
165 #[serde(
167 serialize_with = "serialize_duration",
168 deserialize_with = "deserialize_duration"
169 )]
170 pub total_uptime: Duration,
171
172 #[serde(skip, default = "Instant::now")]
174 pub last_seen: Instant,
175
176 #[serde(skip, default = "Instant::now")]
178 pub first_seen: Instant,
179}
180
181fn serialize_duration<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
182where
183 S: serde::Serializer,
184{
185 serializer.serialize_u64(duration.as_secs())
186}
187
188fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error>
189where
190 D: serde::Deserializer<'de>,
191{
192 let secs = u64::deserialize(deserializer)?;
193 Ok(Duration::from_secs(secs))
194}
195
196impl Default for ReputationScore {
197 fn default() -> Self {
198 let now = Instant::now();
199 Self {
200 transfer_success_rate: 1.0, latency_score: 1.0,
202 protocol_compliance_score: 1.0,
203 uptime_score: 1.0,
204 successful_transfers: 0,
205 failed_transfers: 0,
206 protocol_violations: 0,
207 average_latency_ms: 0,
208 total_uptime: Duration::from_secs(0),
209 last_seen: now,
210 first_seen: now,
211 }
212 }
213}
214
215impl ReputationScore {
216 pub fn overall_score(&self, config: &ReputationConfig) -> f64 {
218 let transfer_score = self.transfer_success_rate * config.transfer_success_weight;
219 let latency_score_weighted = self.latency_score * config.latency_weight;
220 let protocol_score = self.protocol_compliance_score * config.protocol_compliance_weight;
221 let uptime_score_weighted = self.uptime_score * config.uptime_weight;
222
223 transfer_score + latency_score_weighted + protocol_score + uptime_score_weighted
224 }
225
226 fn update_transfer_success_rate(&mut self, success: bool, alpha: f64) {
228 let new_value = if success { 1.0 } else { 0.0 };
229 self.transfer_success_rate = alpha * new_value + (1.0 - alpha) * self.transfer_success_rate;
230
231 if success {
232 self.successful_transfers = self.successful_transfers.saturating_add(1);
233 } else {
234 self.failed_transfers = self.failed_transfers.saturating_add(1);
235 }
236 }
237
238 fn update_latency_score(&mut self, latency_ms: u64, alpha: f64) {
240 let current_avg = self.average_latency_ms as f64;
242 let new_avg = alpha * (latency_ms as f64) + (1.0 - alpha) * current_avg;
243 self.average_latency_ms = new_avg as u64;
244
245 let normalized_latency = (latency_ms as f64).min(1000.0) / 1000.0;
248 self.latency_score = 1.0 - normalized_latency;
249 }
250
251 fn record_protocol_violation(&mut self, alpha: f64) {
253 self.protocol_violations = self.protocol_violations.saturating_add(1);
254
255 self.protocol_compliance_score *= 1.0 - alpha;
257 }
258
259 fn update_uptime(&mut self, connected_duration: Duration) {
261 self.total_uptime += connected_duration;
262
263 let known_duration = self.last_seen.duration_since(self.first_seen);
265 if known_duration.as_secs() > 0 {
266 self.uptime_score =
267 (self.total_uptime.as_secs_f64() / known_duration.as_secs_f64()).min(1.0);
268 }
269 }
270
271 fn apply_decay(&mut self, decay_rate: f64) {
273 let decay_factor = 1.0 - decay_rate;
274 self.transfer_success_rate *= decay_factor;
275 self.latency_score *= decay_factor;
276 self.protocol_compliance_score *= decay_factor;
277 self.uptime_score *= decay_factor;
278 }
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283pub enum ReputationEvent {
284 SuccessfulTransfer,
286 FailedTransfer,
288 LowLatency,
290 HighLatency,
292 ProtocolViolation,
294 GracefulDisconnect,
296 UnexpectedDisconnect,
298}
299
300pub struct ReputationManager {
302 config: ReputationConfig,
303 reputations: DashMap<PeerId, ReputationScore>,
304 stats: parking_lot::RwLock<ReputationStats>,
305}
306
307impl ReputationManager {
308 pub fn new(config: ReputationConfig) -> Self {
310 Self {
311 config,
312 reputations: DashMap::new(),
313 stats: parking_lot::RwLock::new(ReputationStats::default()),
314 }
315 }
316
317 pub fn get_reputation(&self, peer_id: &PeerId) -> Option<ReputationScore> {
319 self.reputations.get(peer_id).map(|entry| entry.clone())
320 }
321
322 pub fn is_trusted(&self, peer_id: &PeerId) -> bool {
324 self.reputations
325 .get(peer_id)
326 .map(|score| score.overall_score(&self.config) >= self.config.trust_threshold)
327 .unwrap_or(false)
328 }
329
330 pub fn is_bad_peer(&self, peer_id: &PeerId) -> bool {
332 self.reputations
333 .get(peer_id)
334 .map(|score| score.overall_score(&self.config) < self.config.bad_peer_threshold)
335 .unwrap_or(false)
336 }
337
338 pub fn get_trusted_peers(&self) -> Vec<PeerId> {
340 self.reputations
341 .iter()
342 .filter(|entry| {
343 entry.value().overall_score(&self.config) >= self.config.trust_threshold
344 })
345 .map(|entry| *entry.key())
346 .collect()
347 }
348
349 pub fn get_bad_peers(&self) -> Vec<PeerId> {
351 self.reputations
352 .iter()
353 .filter(|entry| {
354 entry.value().overall_score(&self.config) < self.config.bad_peer_threshold
355 })
356 .map(|entry| *entry.key())
357 .collect()
358 }
359
360 pub fn record_successful_transfer(&mut self, peer_id: &PeerId, _bytes: u64) {
362 let mut score = self.reputations.entry(*peer_id).or_default();
363 score.update_transfer_success_rate(true, self.config.ema_alpha);
364 score.last_seen = Instant::now();
365
366 let mut stats = self.stats.write();
367 stats.successful_events += 1;
368 }
369
370 pub fn record_failed_transfer(&mut self, peer_id: &PeerId) {
372 let mut score = self.reputations.entry(*peer_id).or_default();
373 score.update_transfer_success_rate(false, self.config.ema_alpha);
374 score.last_seen = Instant::now();
375
376 let mut stats = self.stats.write();
377 stats.failed_events += 1;
378 }
379
380 pub fn record_low_latency(&mut self, peer_id: &PeerId, latency_ms: u64) {
382 let mut score = self.reputations.entry(*peer_id).or_default();
383 score.update_latency_score(latency_ms, self.config.ema_alpha);
384 score.last_seen = Instant::now();
385
386 let mut stats = self.stats.write();
387 stats.latency_updates += 1;
388 }
389
390 pub fn record_protocol_violation(&mut self, peer_id: &PeerId) {
392 let mut score = self.reputations.entry(*peer_id).or_default();
393 score.record_protocol_violation(self.config.ema_alpha);
394 score.last_seen = Instant::now();
395
396 let mut stats = self.stats.write();
397 stats.protocol_violations += 1;
398 }
399
400 pub fn update_uptime(&mut self, peer_id: &PeerId, duration: Duration) {
402 let mut score = self.reputations.entry(*peer_id).or_default();
403 score.update_uptime(duration);
404 score.last_seen = Instant::now();
405
406 let mut stats = self.stats.write();
407 stats.uptime_updates += 1;
408 }
409
410 pub fn record_event(&mut self, peer_id: &PeerId, event: ReputationEvent) {
412 match event {
413 ReputationEvent::SuccessfulTransfer => self.record_successful_transfer(peer_id, 0),
414 ReputationEvent::FailedTransfer => self.record_failed_transfer(peer_id),
415 ReputationEvent::LowLatency => self.record_low_latency(peer_id, 50),
416 ReputationEvent::HighLatency => self.record_low_latency(peer_id, 500),
417 ReputationEvent::ProtocolViolation => self.record_protocol_violation(peer_id),
418 ReputationEvent::GracefulDisconnect => {
419 if let Some(mut score) = self.reputations.get_mut(peer_id) {
421 score.last_seen = Instant::now();
422 }
423 }
424 ReputationEvent::UnexpectedDisconnect => {
425 self.record_failed_transfer(peer_id);
427 }
428 }
429 }
430
431 pub fn apply_decay(&mut self) {
433 for mut entry in self.reputations.iter_mut() {
434 entry.value_mut().apply_decay(self.config.score_decay_rate);
435 }
436 }
437
438 pub fn cleanup_stale(&mut self) -> usize {
440 let retention = self.config.retention_period;
441 let now = Instant::now();
442 let mut removed = 0;
443
444 self.reputations.retain(|_, score| {
445 let should_keep = now.duration_since(score.last_seen) < retention;
446 if !should_keep {
447 removed += 1;
448 }
449 should_keep
450 });
451
452 if removed > 0 {
453 let mut stats = self.stats.write();
454 stats.peers_removed += removed as u64;
455 }
456
457 removed
458 }
459
460 pub fn tracked_peer_count(&self) -> usize {
462 self.reputations.len()
463 }
464
465 pub fn stats(&self) -> ReputationStats {
467 self.stats.read().clone()
468 }
469
470 pub fn clear(&mut self) {
472 self.reputations.clear();
473 *self.stats.write() = ReputationStats::default();
474 }
475}
476
477#[derive(Debug, Clone, Default, Serialize, Deserialize)]
479pub struct ReputationStats {
480 pub successful_events: u64,
482
483 pub failed_events: u64,
485
486 pub protocol_violations: u64,
488
489 pub latency_updates: u64,
491
492 pub uptime_updates: u64,
494
495 pub peers_removed: u64,
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502
503 #[test]
504 fn test_reputation_config_presets() {
505 let strict = ReputationConfig::strict();
506 assert!(strict.trust_threshold > ReputationConfig::default().trust_threshold);
507
508 let lenient = ReputationConfig::lenient();
509 assert!(lenient.trust_threshold < ReputationConfig::default().trust_threshold);
510
511 let perf = ReputationConfig::performance_focused();
512 assert!(perf.latency_weight > ReputationConfig::default().latency_weight);
513 }
514
515 #[test]
516 fn test_reputation_score_default() {
517 let score = ReputationScore::default();
518 assert_eq!(score.transfer_success_rate, 1.0);
519 assert_eq!(score.successful_transfers, 0);
520 assert_eq!(score.failed_transfers, 0);
521 }
522
523 #[test]
524 fn test_reputation_score_overall() {
525 let config = ReputationConfig::default();
526 let score = ReputationScore::default();
527
528 let overall = score.overall_score(&config);
529 assert!(overall > 0.9); }
531
532 #[test]
533 fn test_successful_transfer_updates() {
534 let config = ReputationConfig::default();
535 let mut manager = ReputationManager::new(config);
536 let peer = PeerId::random();
537
538 manager.record_successful_transfer(&peer, 1024);
539
540 let score = manager.get_reputation(&peer).unwrap();
541 assert_eq!(score.successful_transfers, 1);
542 assert_eq!(score.failed_transfers, 0);
543 }
544
545 #[test]
546 fn test_failed_transfer_updates() {
547 let config = ReputationConfig::default();
548 let mut manager = ReputationManager::new(config);
549 let peer = PeerId::random();
550
551 manager.record_failed_transfer(&peer);
552
553 let score = manager.get_reputation(&peer).unwrap();
554 assert_eq!(score.failed_transfers, 1);
555 assert!(score.transfer_success_rate < 1.0);
556 }
557
558 #[test]
559 fn test_latency_scoring() {
560 let config = ReputationConfig::default();
561 let mut manager = ReputationManager::new(config);
562 let peer = PeerId::random();
563
564 manager.record_low_latency(&peer, 50);
566 let score = manager.get_reputation(&peer).unwrap();
567 assert!(score.latency_score > 0.9);
568
569 manager.record_low_latency(&peer, 900);
571 let score = manager.get_reputation(&peer).unwrap();
572 assert!(score.latency_score < 0.5);
573 }
574
575 #[test]
576 fn test_protocol_violation() {
577 let config = ReputationConfig::default();
578 let mut manager = ReputationManager::new(config);
579 let peer = PeerId::random();
580
581 manager.record_protocol_violation(&peer);
582
583 let score = manager.get_reputation(&peer).unwrap();
584 assert_eq!(score.protocol_violations, 1);
585 assert!(score.protocol_compliance_score < 1.0);
586 }
587
588 #[test]
589 fn test_is_trusted() {
590 let config = ReputationConfig::default();
591 let mut manager = ReputationManager::new(config);
592 let peer = PeerId::random();
593
594 manager.record_successful_transfer(&peer, 1024);
596 assert!(manager.is_trusted(&peer));
597
598 for _ in 0..10 {
600 manager.record_failed_transfer(&peer);
601 }
602 assert!(!manager.is_trusted(&peer));
603 }
604
605 #[test]
606 fn test_is_bad_peer() {
607 let config = ReputationConfig {
609 transfer_success_weight: 0.9, ema_alpha: 0.5, latency_weight: 0.05,
612 protocol_compliance_weight: 0.025,
613 uptime_weight: 0.025,
614 ..Default::default()
615 };
616
617 let mut manager = ReputationManager::new(config);
618 let peer = PeerId::random();
619
620 for _ in 0..20 {
622 manager.record_failed_transfer(&peer);
623 }
624
625 assert!(manager.is_bad_peer(&peer));
626 }
627
628 #[test]
629 fn test_get_trusted_peers() {
630 let config = ReputationConfig::default();
631 let mut manager = ReputationManager::new(config);
632
633 let peer1 = PeerId::random();
634 let peer2 = PeerId::random();
635
636 manager.record_successful_transfer(&peer1, 1024);
637 manager.record_successful_transfer(&peer2, 1024);
638
639 let trusted = manager.get_trusted_peers();
640 assert_eq!(trusted.len(), 2);
641 }
642
643 #[test]
644 fn test_get_bad_peers() {
645 let config = ReputationConfig {
647 transfer_success_weight: 0.9,
648 ema_alpha: 0.5,
649 latency_weight: 0.05,
650 protocol_compliance_weight: 0.025,
651 uptime_weight: 0.025,
652 ..Default::default()
653 };
654
655 let mut manager = ReputationManager::new(config);
656
657 let peer = PeerId::random();
658
659 for _ in 0..20 {
660 manager.record_failed_transfer(&peer);
661 }
662
663 let bad_peers = manager.get_bad_peers();
664 assert_eq!(bad_peers.len(), 1);
665 }
666
667 #[test]
668 fn test_uptime_tracking() {
669 let config = ReputationConfig::default();
670 let mut manager = ReputationManager::new(config);
671 let peer = PeerId::random();
672
673 manager.update_uptime(&peer, Duration::from_secs(3600));
674
675 let score = manager.get_reputation(&peer).unwrap();
676 assert_eq!(score.total_uptime.as_secs(), 3600);
677 }
678
679 #[test]
680 fn test_reputation_events() {
681 let config = ReputationConfig::default();
682 let mut manager = ReputationManager::new(config);
683 let peer = PeerId::random();
684
685 manager.record_event(&peer, ReputationEvent::SuccessfulTransfer);
686 manager.record_event(&peer, ReputationEvent::LowLatency);
687 manager.record_event(&peer, ReputationEvent::ProtocolViolation);
688
689 let score = manager.get_reputation(&peer).unwrap();
690 assert!(score.successful_transfers > 0);
691 assert!(score.protocol_violations > 0);
692 }
693
694 #[test]
695 fn test_stats_tracking() {
696 let config = ReputationConfig::default();
697 let mut manager = ReputationManager::new(config);
698 let peer = PeerId::random();
699
700 manager.record_successful_transfer(&peer, 1024);
701 manager.record_failed_transfer(&peer);
702 manager.record_protocol_violation(&peer);
703
704 let stats = manager.stats();
705 assert_eq!(stats.successful_events, 1);
706 assert_eq!(stats.failed_events, 1);
707 assert_eq!(stats.protocol_violations, 1);
708 }
709
710 #[test]
711 fn test_tracked_peer_count() {
712 let config = ReputationConfig::default();
713 let mut manager = ReputationManager::new(config);
714
715 for _ in 0..5 {
716 let peer = PeerId::random();
717 manager.record_successful_transfer(&peer, 1024);
718 }
719
720 assert_eq!(manager.tracked_peer_count(), 5);
721 }
722
723 #[test]
724 fn test_clear() {
725 let config = ReputationConfig::default();
726 let mut manager = ReputationManager::new(config);
727 let peer = PeerId::random();
728
729 manager.record_successful_transfer(&peer, 1024);
730 assert_eq!(manager.tracked_peer_count(), 1);
731
732 manager.clear();
733 assert_eq!(manager.tracked_peer_count(), 0);
734 }
735}