A Python port of the Invisible Internet Project (I2P)
at main 103 lines 3.3 kB view raw
1"""Peer score calculators. 2 3Ported from net.i2p.router.peermanager.CapacityCalculator etc. 4""" 5 6from __future__ import annotations 7 8from typing import TYPE_CHECKING 9 10if TYPE_CHECKING: 11 from i2p_peer.profile import PeerProfile 12 13 14class CapacityCalculator: 15 """Compute tunnel-building capacity score from peer history.""" 16 17 @staticmethod 18 def calc(profile: PeerProfile) -> float: 19 """Capacity = weighted combination of tunnel success rate and send rate. 20 21 Range: 0.0 to 1.0. 22 23 Weighting: 24 - Tunnel build success: 40% 25 - Send success: 30% 26 - DB operation success: 20% 27 - Uptime/activity: 10% 28 """ 29 tunnel_total = profile.tunnel_builds_succeeded + profile.tunnel_builds_failed 30 send_total = profile.send_success_count + profile.send_failure_count 31 db_total = (profile.db_store_success_count + profile.db_store_failure_count + 32 profile.db_lookup_success_count + profile.db_lookup_failure_count) 33 34 # If no history at all, return 0 35 if tunnel_total == 0 and send_total == 0 and db_total == 0: 36 return 0.0 37 38 tunnel_score = profile.tunnel_success_rate if tunnel_total > 0 else 0.0 39 send_score = profile.send_success_rate if send_total > 0 else 0.0 40 db_score = profile.db_success_rate if db_total > 0 else 0.0 41 42 # Activity score: 1.0 if heard from recently, 0.0 otherwise 43 activity_score = 1.0 if profile.last_heard_from > 0.0 else 0.0 44 45 # Weight components that have data 46 total_weight = 0.0 47 weighted_sum = 0.0 48 49 if tunnel_total > 0: 50 weighted_sum += tunnel_score * 0.4 51 total_weight += 0.4 52 if send_total > 0: 53 weighted_sum += send_score * 0.3 54 total_weight += 0.3 55 if db_total > 0: 56 weighted_sum += db_score * 0.2 57 total_weight += 0.2 58 59 weighted_sum += activity_score * 0.1 60 total_weight += 0.1 61 62 if total_weight == 0.0: 63 return 0.0 64 65 return min(1.0, max(0.0, weighted_sum / total_weight)) 66 67 68class SpeedCalculator: 69 """Compute speed score from latency measurements.""" 70 71 # Reference latency: 1000ms. Latency at or below gets high score. 72 REFERENCE_LATENCY_MS = 1000.0 73 74 @staticmethod 75 def calc(profile: PeerProfile) -> float: 76 """Speed = inverse of average latency, normalized 0.0 to 1.0. 77 78 Lower latency = higher speed score. 79 Uses formula: score = reference / (reference + avg_latency) 80 """ 81 avg = profile.average_latency 82 if avg <= 0.0: 83 return 0.0 84 # Sigmoid-like normalization: ref / (ref + latency) 85 # 50ms -> 1000/1050 = 0.952 86 # 500ms -> 1000/1500 = 0.667 87 # 1000ms -> 1000/2000 = 0.5 88 # 5000ms -> 1000/6000 = 0.167 89 return min(1.0, max(0.0, 90 SpeedCalculator.REFERENCE_LATENCY_MS / 91 (SpeedCalculator.REFERENCE_LATENCY_MS + avg))) 92 93 94class IntegrationCalculator: 95 """Compute integration score (how well-connected the peer is).""" 96 97 @staticmethod 98 def calc(profile: PeerProfile) -> float: 99 """Integration = DB store/lookup success rate. 100 101 High integration = good floodfill candidate. 102 """ 103 return profile.db_success_rate