block.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import json
  2. import time
  3. from ouroboros.utils import encode_genesis_data, decode_gensis_data, state_hash
  4. from ouroboros.consts import *
  5. from ouroboros.logger import Logger
  6. '''
  7. single block B_i for slot i in the system live time L,
  8. assigned to stakeholder U_j, with propability P_j_i,
  9. in the chain C, should be signed by U_j keys.
  10. '''
  11. class Block(object):
  12. '''
  13. @param previous_block: parent block to the current block
  14. @param data: is the transaction, or contracts in the leadger, or gensis block data,
  15. data is expected to be binary, no format is enforced
  16. @param slot_uid: the block corresponding slot monotonically increasing index,
  17. it's one-based
  18. @param gensis: boolean, True for gensis block
  19. '''
  20. def __init__(self, previous_block, data, slot_uid, genesis_time=time.time(), genesis=False):
  21. # state is hte hash of the previous block in the blockchain
  22. self.state=''
  23. if slot_uid>1:
  24. self.state=state_hash(previous_block)
  25. self.tx = data
  26. self.sl = slot_uid
  27. self.signature = None # block issuer signature
  28. self.sigma = None # proof that the block is valid.
  29. self.is_genesis=genesis
  30. self.endorsed=False
  31. self.log = Logger(genesis_time)
  32. self.leader_id=None
  33. self.endorser_id=None
  34. @property
  35. def slot(self):
  36. return self.sl
  37. def __repr__(self):
  38. if self.is_genesis:
  39. return "GensisBlock " + str(self.__to_dict)
  40. return "Block " + str(self.__to_dict)
  41. @property
  42. def __to_dict(self):
  43. return {SLOT: self.st, STATE: self.state, DATA: self.tx, PROOF: self.sigma, SIGN: self.signature}
  44. def __hash__(self):
  45. if type(self.tx)==str:
  46. return hash((self.state, self.tx, self.sl))
  47. elif type(self.tx)==dict:
  48. return hash((self.state, self.tx[SEED], self.tx[TX]))
  49. else:
  50. return hash(str(self))
  51. def __eq__(self, block):
  52. return self.state==block.state and \
  53. self.tx == block.tx and \
  54. self.sl == block.sl
  55. def to_json(self):
  56. d = self.__to_dict
  57. return json.encoder(d)
  58. def set_endorsed(self):
  59. self.endorsed=True
  60. def set_endorser(self, id):
  61. self.endorser_id=id
  62. self.set_endorsed()
  63. def set_leader(self, id):
  64. self.leader_id=id
  65. def set_sigma(self, sigma):
  66. self.sigma = sigma
  67. def set_signature(self, sign):
  68. self.signature = sign
  69. @property
  70. def data(self):
  71. return self.tx
  72. @property
  73. def slot(self):
  74. return self.sl
  75. @property
  76. def empty(self):
  77. return (self.tx=='' or self.slot<0) and self.state==''
  78. def encode(self):
  79. return str(self.__to_dict).encode()
  80. class GensisBlock(Block):
  81. '''
  82. @param data: data is dictionary of list of (pk_i, s_i) public key,
  83. and stake respectively of the corresponding stakeholder U_i,
  84. seed of the leader election function.
  85. '''
  86. def __init__(self, previous_block, data, slot_uid, genesis_time=time.time()):
  87. # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
  88. dist_block = data[0]
  89. self.stakeholders = dist_block[STAKEHOLDERS]
  90. self.distribution = dist_block[STAKEHOLDERS_DISTRIBUTIONS]
  91. self.seed = dist_block[SEED] #needed for pvss
  92. shd_buff = ''
  93. for shd in self.distribution:
  94. shd_buff +=str(shd)
  95. #data = encode_genesis_data(shd_buff)
  96. data_dict = {'seed':self.seed, 'distribution':shd_buff}
  97. Block.__init__(self, previous_block, str(data_dict), slot_uid, genesis_time, True)
  98. '''
  99. @return: the number of participating stakeholders in the blockchain
  100. '''
  101. @property
  102. def length(self):
  103. return len(self.stakeholders)
  104. def __getitem__(self, i):
  105. if i<0 or i>=self.length:
  106. raise "index is out of range!"
  107. return self.stakeholders[i]
  108. '''
  109. block lead by an adversary, or
  110. lead by offline leader
  111. is an empty Block
  112. '''
  113. class EmptyBlock(Block):
  114. def __init__(self, genesis_time=time.time()):
  115. Block.__init__(self, '', -1, genesis_time, False)