stakeholder.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #from asyncio.log import logger
  2. from ouroboros.block import Block, GensisBlock, EmptyBlock
  3. from ouroboros.blockchain import Blockchain
  4. from ouroboros.epoch import Epoch
  5. from ouroboros.beacon import TrustedBeacon
  6. from ouroboros.vrf import verify, VRF
  7. from ouroboros.utils import *
  8. from ouroboros.logger import Logger
  9. from ouroboros.consts import *
  10. import time
  11. '''
  12. \class Stakeholder
  13. '''
  14. class Stakeholder(object):
  15. def __init__(self, epoch_length=2, passwd='password'):
  16. #TODO (fix) remove redundant variables reley on environment
  17. self.passwd=passwd
  18. self.stake=0
  19. self.epoch_length=epoch_length
  20. self.vrf = VRF(self.passwd)
  21. #verification keys
  22. self.__vrf_pk = self.vrf.pk
  23. self.__vrf_sk = self.vrf.sk
  24. self.__vrf_base = self.vrf.g
  25. #signature keys
  26. sig_sk, sig_pk = generate_sig_keys(self.passwd)
  27. self.sig_sk = sig_sk
  28. self.sig_pk = sig_pk
  29. #
  30. self.current_block = None
  31. self.uncommited_tx=''
  32. self.tx=''
  33. self.current_epoch = None
  34. self.am_current_leader=False
  35. self.am_current_endorder=False
  36. self.am_corrupt=False
  37. #
  38. @property
  39. def is_leader(self):
  40. return self.am_current_leader
  41. @property
  42. def vrf_pk(self):
  43. return self.__vrf_pk
  44. @property
  45. def vrf_base(self):
  46. return self.__vrf_base
  47. def __repr__(self):
  48. buff = f"\tstakeholder with stake:{self.stake}\t"
  49. return buff
  50. def __call__(self, env):
  51. self.env=env
  52. self.log = Logger(self, self.env.genesis_time)
  53. self.blockchain = Blockchain(self.epoch_length, self.env.genesis_time)
  54. self.beacon = TrustedBeacon(self, self.vrf, self.epoch_length, self.env.genesis_time)
  55. self.current_slot_uid = self.beacon.slot
  56. def start(self):
  57. self.log.info("start [started]")
  58. self.beacon.start()
  59. self.log.info("start [ended]")
  60. @property
  61. def epoch_index(self):
  62. return round(self.current_slot_uid/self.epoch_length)
  63. def __gen_genesis_epoch(self):
  64. '''
  65. '''
  66. self.tx = self.env.get_genesis_data()
  67. self.tx[TX]=self.uncommited_tx
  68. self.uncommited_tx=''
  69. self.current_block=GensisBlock(self.current_block, self.tx, self.current_slot_uid)
  70. self.current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch_index, self.env.genesis_time)
  71. '''
  72. it's a callback function, and called by the diffuser
  73. '''
  74. def new_epoch(self, slot, sigmas, proofs):
  75. '''
  76. #TODO implement praos
  77. for this implementation we assume synchrony,
  78. and at this point, and no delay is considered (for simplicity)
  79. '''
  80. self.log.highlight("<new_epoch> start")
  81. self.env.new_epoch(slot, sigmas, proofs)
  82. self.current_slot_uid = slot
  83. #kickoff gensis block
  84. # add old epoch to the ledger
  85. if self.current_slot_uid > 1 and self.current_epoch!=None and len(self.current_epoch)>0:
  86. self.blockchain.add_epoch(self.current_epoch)
  87. #if leader, you need to broadcast the block
  88. self.__gen_genesis_epoch()
  89. if self.am_current_leader:
  90. self.broadcast_block()
  91. '''
  92. it's a callback function, and called by the diffuser
  93. '''
  94. def new_slot(self, slot, sigma, proof):
  95. '''
  96. #TODO implement praos
  97. for this implementation we assume synchrony,
  98. and at this point, and no delay is considered (for simplicity)
  99. '''
  100. self.log.highlight("<new_slot> start")
  101. self.env.new_slot(slot, sigma, proof)
  102. vrf_pk = self.env.current_leader_vrf_pk
  103. vrf_g = self.env.current_leader_vrf_g
  104. assert(vrf_pk!=None)
  105. assert(vrf_g!=None)
  106. if not verify(slot, sigma, proof, vrf_pk,vrf_g) :
  107. #TODO the leader is corrupted, action to be taken against the corrupt stakeholder
  108. #in this case this slot is empty
  109. self.current_block=EmptyBlock()
  110. if self.current_epoch!=None:
  111. self.current_epoch.add_block(self.current_block)
  112. else:
  113. self.log.warn(f"<new_slot> current_epoch is None!")
  114. return
  115. if self.current_epoch==None:
  116. self.log.warn(f"<new_slot> current_epoch is None!")
  117. self.__gen_genesis_epoch()
  118. self.current_slot_uid = slot
  119. self.current_block=Block(self.current_block, self.tx, self.current_slot_uid)
  120. self.current_epoch.add_block(self.current_block)
  121. if self.am_current_leader:
  122. self.broadcast_block()
  123. def set_leader(self):
  124. self.am_current_leader=True
  125. def set_endorser(self):
  126. self.am_endorser=True
  127. def set_corrupt(self):
  128. self.am_corrupt=False
  129. def broadcast_block(self):
  130. self.log.highlight("broadcasting block")
  131. assert(self.am_current_leader)
  132. signed_block = sign_message(self.passwd, self.sig_sk, self.current_block)
  133. self.env.broadcast_block(signed_block)
  134. self.env.print_blockchain()
  135. def receive_block(self, received_block):
  136. self.log.highlight("receiving block")
  137. if verify_signature(self.env.current_leader_sig_pk, self.current_block, received_block):
  138. pass
  139. else:
  140. self.env.corrupt(self.env.current_leader_id)
  141. self.env.print_blockchain()