stakeholder.py 4.8 KB

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