environment.py 4.7 KB

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