|
@@ -171,7 +171,45 @@ class Simulator:
|
|
|
for r in self.relays: r.perfstats.reset()
|
|
|
for c in self.clients: c.perfstats.reset()
|
|
|
|
|
|
- # TODO: churn relays and clients
|
|
|
+ # Churn relays
|
|
|
+
|
|
|
+ # Churn is controlled by three parameters:
|
|
|
+ # newmean: the mean number of new arrivals per epoch
|
|
|
+ # newstddev: the stddev number of new arrivals per epoch
|
|
|
+ # oldprob: the probability any given existing one leaves per epoch
|
|
|
+
|
|
|
+ # If target is the desired steady state number, then it should
|
|
|
+ # be the case that target * oldprob = newmean. That way, if the
|
|
|
+ # current number is below target, on average you add more than
|
|
|
+ # you remove, and if the current number is above target, on
|
|
|
+ # average you add fewer than you remove.
|
|
|
+
|
|
|
+ # For relays, looking at all the consensuses for Nov and Dec
|
|
|
+ # 2019, newmean is about 1.0% of the network size, and newstddev
|
|
|
+ # is about 0.3% of the network size.
|
|
|
+ relay_newmean = 0.010 * self.relaytarget
|
|
|
+ relay_newstddev = 0.003 * self.relaytarget
|
|
|
+ relay_oldprob = 0.010
|
|
|
+
|
|
|
+ # Stop some of the (non-fallback) relays
|
|
|
+ relays_terminating = []
|
|
|
+ for r in self.relays:
|
|
|
+ if not r.is_fallbackrelay and random.random() < relay_oldprob:
|
|
|
+ relays_terminating.append(r)
|
|
|
+
|
|
|
+ for r in relays_terminating:
|
|
|
+ r.terminate()
|
|
|
+ self.relays.remove(r)
|
|
|
+
|
|
|
+ # Start some new relays
|
|
|
+ relays_new = int(random.normalvariate(relay_newmean, relay_newstddev))
|
|
|
+ if relays_new > 0:
|
|
|
+ for i in range(relays_new):
|
|
|
+ x = random.randint(1,2500)
|
|
|
+ bw = int(200000-(200000-25000)/3*math.log10(x))
|
|
|
+ self.relays.append(relay.Relay(self.dirauthaddrs, bw, 0))
|
|
|
+
|
|
|
+ # TODO: churn clients
|
|
|
|
|
|
# Tick the epoch
|
|
|
network.thenetwork.nextepoch()
|