beacon.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import threading
  2. from ouroboros.clock import SynchedNTPClock
  3. from ouroboros.vrf import VRF
  4. from ouroboros.logger import Logger
  5. '''
  6. \class TrustedBeacon
  7. the trusted beacon is decentralized, such that at the onset of the Epoch,
  8. the leader of the first slot generated the signed seed, and release the signature,
  9. proof, and base to the genesis block.
  10. #TODO implement trustedbeacon as a node
  11. '''
  12. class TrustedBeacon(SynchedNTPClock, threading.Thread):
  13. def __init__(self, node, vrf, epoch_length, genesis_time):
  14. self.epoch_length=epoch_length # how many slots in a a block
  15. SynchedNTPClock.__init__(self)
  16. threading.Thread.__init__(self)
  17. self.daemon=True
  18. self.node = node #stakeholder
  19. self.vrf = vrf
  20. self.current_slot = self.slot
  21. self.log = Logger(self, genesis_time)
  22. self.log.info(f"constructed for node {str(node)}")
  23. self.bb=0 # epoch counts since genesis (big bang)
  24. def __repr__(self):
  25. return f"trustedbeacon"
  26. def run(self):
  27. self.log.highlight("thread [start]")
  28. self.__background()
  29. self.log.info("thread [end]")
  30. def __background(self):
  31. current_epoch = self.slot
  32. self.log.info('background waiting for the onset of next synched epoch...')
  33. while True:
  34. if self.slot != current_epoch:
  35. current_epoch = self.slot
  36. self.__callback()
  37. def __callback(self):
  38. self.current_slot = self.slot
  39. if self.current_slot%self.epoch_length!=0:
  40. if self.bb==0:
  41. # new nodes attached to the network, need to either request old blocks, or wait for next epoch's broadcst
  42. # it's temporarily, and or simplicity set to the latter
  43. return
  44. self.log.info(f"callback: new slot of idx: {self.current_slot}")
  45. #y, pi = self.vrf.sign(self.current_slot)
  46. self.log.info(f"callbaxck: signature calculated for {str(self.node)}")
  47. self.node.new_slot(self.current_slot)
  48. else:
  49. self.bb+=1
  50. sigmas = []
  51. proofs = []
  52. #TODO since it's expensive, but to generate single (y,pi) pair as seed
  53. # and use random hash function to generate the rest randomly.
  54. if self.node.am_current_leader:
  55. for i in range(self.epoch_length):
  56. self.log.info(f"callback: new slot of idx: {self.current_slot}, epoch slot {i}")
  57. y, pi = self.vrf.sign(self.current_slot)
  58. self.log.info(f"callback: signature calculated for {str(self.node)}")
  59. sigmas.append(y)
  60. proofs.append(pi)
  61. self.node.new_epoch(self.current_slot, sigmas, proofs)
  62. def verify(self, y, pi, pk_raw, g):
  63. return VRF.verify(self.current_slot, y, pi, pk_raw, g)