|
@@ -28,6 +28,33 @@ class Simulator:
|
|
|
# Mean number of circuits created per client per epoch
|
|
|
self.gamma = 8.9
|
|
|
|
|
|
+ # 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.
|
|
|
+ self.relay_newmean = 0.010 * self.relaytarget
|
|
|
+ self.relay_newstddev = 0.003 * self.relaytarget
|
|
|
+ self.relay_oldprob = 0.010
|
|
|
+
|
|
|
+ # For clients, looking at how many clients request a consensus
|
|
|
+ # with an if-modified-since date more than 3 hours old (and so
|
|
|
+ # we treat them as "new") over several days in late Dec 2019,
|
|
|
+ # newmean is about 16% of all clients, and newstddev is about 4%
|
|
|
+ # of all clients.
|
|
|
+ self.client_newmean = 0.16 * self.clienttarget
|
|
|
+ self.client_newstddev = 0.04 * self.clienttarget
|
|
|
+ self.client_oldprob = 0.16
|
|
|
+
|
|
|
# Start some dirauths
|
|
|
self.dirauthaddrs = []
|
|
|
self.dirauths = []
|
|
@@ -176,36 +203,31 @@ class Simulator:
|
|
|
|
|
|
# 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)
|
|
|
+ relays_remaining = []
|
|
|
+ numrelays = len(self.relays)
|
|
|
+ numrelaysterminated = 0
|
|
|
+ lastpercent = 0
|
|
|
+ logging.info("Terminating some relays")
|
|
|
+ for i, r in enumerate(self.relays):
|
|
|
+ percent = int(100*(i+1)/numrelays)
|
|
|
+ if not r.is_fallbackrelay and \
|
|
|
+ random.random() < self.relay_oldprob:
|
|
|
+ r.terminate()
|
|
|
+ numrelaysterminated += 1
|
|
|
+ else:
|
|
|
+ # Keep this relay
|
|
|
+ relays_remaining.append(r)
|
|
|
+ if percent != lastpercent:
|
|
|
+ lastpercent = percent
|
|
|
+ logging.info("%d%% relays considered, %d terminated",
|
|
|
+ percent, numrelaysterminated)
|
|
|
+ self.relays = relays_remaining
|
|
|
|
|
|
# Start some new relays
|
|
|
- relays_new = int(random.normalvariate(relay_newmean, relay_newstddev))
|
|
|
+ relays_new = int(random.normalvariate(self.relay_newmean,
|
|
|
+ self.relay_newstddev))
|
|
|
+ logging.info("Starting %d new relays", relays_new)
|
|
|
if relays_new > 0:
|
|
|
for i in range(relays_new):
|
|
|
x = random.randint(1,2500)
|
|
@@ -214,6 +236,34 @@ class Simulator:
|
|
|
|
|
|
# TODO: churn clients
|
|
|
|
|
|
+ # Stop some of the clients
|
|
|
+ clients_remaining = []
|
|
|
+ numclients = len(self.clients)
|
|
|
+ numclientsterminated = 0
|
|
|
+ lastpercent = 0
|
|
|
+ logging.info("Terminating some clients")
|
|
|
+ for i, c in enumerate(self.clients):
|
|
|
+ percent = int(100*(i+1)/numclients)
|
|
|
+ if random.random() < self.client_oldprob:
|
|
|
+ c.terminate()
|
|
|
+ numclientsterminated += 1
|
|
|
+ else:
|
|
|
+ # Keep this client
|
|
|
+ clients_remaining.append(c)
|
|
|
+ if percent != lastpercent:
|
|
|
+ lastpercent = percent
|
|
|
+ logging.info("%d%% clients considered, %d terminated",
|
|
|
+ percent, numclientsterminated)
|
|
|
+ self.clients = clients_remaining
|
|
|
+
|
|
|
+ # Start some new clients
|
|
|
+ clients_new = int(random.normalvariate(self.client_newmean,
|
|
|
+ self.client_newstddev))
|
|
|
+ logging.info("Starting %d new clients", clients_new)
|
|
|
+ if clients_new > 0:
|
|
|
+ for i in range(clients_new):
|
|
|
+ self.clients.append(client.Client(self.dirauthaddrs))
|
|
|
+
|
|
|
# Tick the epoch
|
|
|
network.thenetwork.nextepoch()
|
|
|
|