simulator.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/env python3
  2. import random # For simulation, not cryptography!
  3. import math
  4. import sys
  5. import logging
  6. import resource
  7. import network
  8. import dirauth
  9. import relay
  10. import client
  11. class Simulator:
  12. def __init__(self, relaytarget, clienttarget):
  13. self.relaytarget = relaytarget
  14. self.clienttarget = clienttarget
  15. # Some (for now) hard-coded parameters
  16. # The number of directory authorities
  17. numdirauths = 9
  18. # The fraction of relays that are fallback relays
  19. fracfallbackrelays = 0.05
  20. # Start some dirauths
  21. self.dirauthaddrs = []
  22. self.dirauths = []
  23. for i in range(numdirauths):
  24. dira = dirauth.DirAuth(i, numdirauths)
  25. self.dirauths.append(dira)
  26. self.dirauthaddrs.append(dira.netaddr)
  27. # Start some relays
  28. self.relays = []
  29. for i in range(self.relaytarget):
  30. # Relay bandwidths (at least the ones fast enough to get used)
  31. # in the live Tor network (as of Dec 2019) are well approximated
  32. # by (200000-(200000-25000)/3*log10(x)) where x is a
  33. # uniform integer in [1,2500]
  34. x = random.randint(1,2500)
  35. bw = int(200000-(200000-25000)/3*math.log10(x))
  36. self.relays.append(relay.Relay(self.dirauthaddrs, bw, 0))
  37. # The fallback relays are a hardcoded list of a small fraction
  38. # of the relays, used by clients for bootstrapping
  39. numfallbackrelays = int(self.relaytarget * fracfallbackrelays) + 1
  40. fallbackrelays = random.sample(self.relays, numfallbackrelays)
  41. for r in fallbackrelays:
  42. r.set_is_fallbackrelay()
  43. network.thenetwork.setfallbackrelays(fallbackrelays)
  44. # Tick the epoch to build the first consensus
  45. network.thenetwork.nextepoch()
  46. # Start some clients
  47. self.clients = []
  48. for i in range(clienttarget):
  49. self.clients.append(client.Client(self.dirauthaddrs))
  50. # Tick the epoch to bootstrap the clients
  51. network.thenetwork.nextepoch()
  52. # Throw away all the performance statistics to this point
  53. for d in self.dirauths: d.perfstats.reset()
  54. for r in self.relays: r.perfstats.reset()
  55. for c in self.clients: c.perfstats.reset()
  56. if __name__ == '__main__':
  57. # Args: womode snipauthmode networkscale numepochs randseed
  58. if len(sys.argv) != 6:
  59. sys.stderr.write("Usage: womode snipauthmode networkscale numepochs randseed\n")
  60. sys.exit(1)
  61. womode = network.WOMode[sys.argv[1].upper()]
  62. snipauthmode = network.SNIPAuthMode[sys.argv[2].upper()]
  63. networkscale = float(sys.argv[3])
  64. numepochs = int(sys.argv[4])
  65. randseed = int(sys.argv[5])
  66. # Seed the PRNG. On Ubuntu 18.04, this in fact makes future calls
  67. # to (non-cryptographic) random numbers deterministic. On Ubuntu
  68. # 16.04, it does not.
  69. random.seed(randseed)
  70. # Uncomment to see all the debug messages
  71. # logging.basicConfig(level=logging.DEBUG)
  72. logging.basicConfig(level=logging.INFO)
  73. # Set the Walking Onions style to use
  74. network.thenetwork.set_wo_style(womode, snipauthmode)
  75. # The steady-state numbers of relays and clients
  76. relaytarget = math.ceil(6500 * networkscale)
  77. clienttarget = math.ceil(2500000 * networkscale)
  78. # Create the simulation
  79. simulator = Simulator(relaytarget, clienttarget)
  80. network.thenetwork.nextepoch()
  81. maxmemmib = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/1024
  82. logging.info("%d MiB used", maxmemmib)