Browse Source

Choose a fallback relay weighted by bw, not uniformly

Ian Goldberg 4 years ago
parent
commit
5719b13ea3
2 changed files with 20 additions and 5 deletions
  1. 2 1
      client.py
  2. 18 4
      network.py

+ 2 - 1
client.py

@@ -188,7 +188,8 @@ class ClientChannelManager(relay.ChannelManager):
 
     def get_consensus_from_fallbackrelay(self):
         """Download a fresh consensus from a random fallbackrelay."""
-        fb = random.choice(network.thenetwork.getfallbackrelays())
+        fb = network.thenetwork.getfallbackrelay()
+        logging.debug("Chose fallback %s", fb)
         if network.thenetwork.womode == network.WOMode.VANILLA:
             if self.consensus is not None and \
                     len(self.consensus.consdict['relays']) > 0:

+ 18 - 4
network.py

@@ -4,6 +4,7 @@ import random
 import pickle
 import logging
 import math
+import bisect
 from enum import Enum
 
 # Set this to True if you want the bytes sent and received to be added
@@ -302,10 +303,23 @@ class Network:
         these to bootstrap when they know no other relays."""
         self.fallbackrelays = fallbackrelays
 
-    def getfallbackrelays(self):
-        """Get the list of globally known fallback relays.  Clients use
-        these to bootstrap when they know no other relays."""
-        return self.fallbackrelays
+        # Construct the CDF of fallback relay bws, so that clients can
+        # choose a fallback relay weighted by bw
+        self.fallbackbwcdf = [0]
+        for r in fallbackrelays:
+            self.fallbackbwcdf.append(self.fallbackbwcdf[-1]+r.bw)
+        # Remove the last item, which should be the sum of all the
+        # relays
+        self.fallbacktotbw = self.fallbackbwcdf.pop()
+
+    def getfallbackrelay(self):
+        """Get a random one of the globally known fallback relays,
+        weighted by bw.  Clients use these to bootstrap when they know
+        no other relays."""
+        idx = random.randint(0, self.fallbacktotbw-1)
+        i = bisect.bisect_right(self.fallbackbwcdf, idx)
+        r = self.fallbackrelays[i-1]
+        return r
 
     def set_wo_style(self, womode, snipauthmode):
         """Set the Walking Onions mode and the SNIP authenticate mode