environment.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import numpy as np
  2. import math
  3. import random
  4. from ouroboros.logger import Logger
  5. '''
  6. \class Z is the environment
  7. '''
  8. class Z(object):
  9. def __init__(self, stakeholdes, epoch_length):
  10. self.log = Logger(self)
  11. self.epoch_length=epoch_length
  12. self.stakeholders = np.array(stakeholdes)
  13. self.adversary_mask=np.array([True]*len(stakeholdes))
  14. self.current_epoch_leaders=[-1]*self.epoch_length
  15. self.current_slot=0
  16. self.log.info("Z initialized")
  17. def __repr__(self):
  18. buff= f"envirnment of {self.length} stakholders"
  19. for sh in self.stakeholders:
  20. buff+=str(sh)+"\n"
  21. return buff
  22. '''
  23. return genesis data of the current epoch
  24. '''
  25. def get_genesis_data(self):
  26. #TODO implement dynaming staking
  27. return ''
  28. @property
  29. def current_leader_id(self):
  30. return self.current_slot%self.epoch_length
  31. @property
  32. def current_stakeholder(self):
  33. self.log.info(f"getting leader of id{self.current_leader_id} of size {len(self.stakeholders)}")
  34. return self.stakeholders[self.current_leader_id]
  35. @property
  36. def current_leader_vrf_pk(self):
  37. return self.stakeholders[self.current_leader_id].vrf_pk
  38. @property
  39. def current_leader_vrf_g(self):
  40. return self.stakeholders[self.current_leader_id].vrf_base
  41. #TODO complete
  42. def obfuscate_idx(self, i):
  43. return i
  44. #TODO complete
  45. def deobfuscate_idx(self, i):
  46. return i
  47. def corrupt(self, i):
  48. if i<0 or i>len(self.adversary_mask):
  49. return False
  50. self.adversary_mask[self.deobfuscate_idx(i)]=False
  51. return True
  52. '''
  53. return the length of all parties
  54. '''
  55. def __len__(self):
  56. return len(self.stakeholders)
  57. @property
  58. def length(self):
  59. return len(self.stakeholders)
  60. @property
  61. def honest(self):
  62. return len(self.stakeholders[self.adversary_mask])
  63. def select_epoch_leaders(self, sigmas, proofs):
  64. assert(len(sigmas)==self.epoch_length and len(proofs)==self.epoch_length, \
  65. f"size mismatch between sigmas: {len(sigmas)}, proofs: {len(proofs)}, and epoch_length: {self.epoch_length}")
  66. for i in range(self.epoch_length):
  67. self.log.info(f"current sigma of index {i} of total {len(sigmas)}, epoch_length: {self.epoch_length}")
  68. sigma = sigmas[i]
  69. assert (sigma!=None, 'proof cant be None')
  70. def leader_selection_hash(sigma):
  71. Y = np.array(sigma)
  72. y_hypotenuse2 = math.ceil(np.sum(Y[1]**2+Y[2]**2))
  73. return y_hypotenuse2
  74. seed = leader_selection_hash(sigma)
  75. random.seed(seed)
  76. leader_idx=seed%self.length
  77. # only select an honest leaders
  78. while not self.adversary_mask[leader_idx]:
  79. leader_idx=random.randint(0,self.length)
  80. #TODO select the following leader for this epoch, note,
  81. # under a single condition that no one is able to predict who is next
  82. self.current_epoch_leaders[i]=leader_idx
  83. return self.current_epoch_leaders
  84. def new_slot(self, slot, sigma, proof):
  85. self.current_slot=slot
  86. self.log.info(f"stakeholders: {self.stakeholders}")
  87. current_leader = self.stakeholders[self.current_leader_id]
  88. assert(current_leader!=None, "current leader cant be None")
  89. if current_leader.is_leader:
  90. #pass leadership to the current slot leader from the epoch leader
  91. self.stakeholders[self.current_epoch_leaders[slot%self.epoch_length]].set_leader()
  92. def new_epoch(self, slot, sigmas, proofs):
  93. self.current_slot=slot
  94. #self.log.info(f"stakeholders: {self.stakeholders}")
  95. #current_leader = self.stakeholders[self.current_leader_id]
  96. #assert(current_leader!=None, 'current leader cant be none')
  97. #assert(current_leader.is_leader)
  98. self.select_epoch_leaders(sigmas, proofs)
  99. def broadcast_block(self, signed_block):
  100. for stakeholder in self.stakeholders:
  101. if not stakeholder.is_leader:
  102. self.stakeholders.receive_block(signed_block)
  103. def start(self):
  104. for sh in self.stakeholders:
  105. sh(self)
  106. self.log.info("Z.start [started]")
  107. for sh in self.stakeholders:
  108. sh.start()
  109. self.log.info("Z.start [ended]")
  110. def print_blockchain(self):
  111. bc = self.stakeholders[0].blockchain
  112. self.log.info(f"blockchain of {len(bc)} blocks: "+str(bc))