block.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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.is_genesis=genesis
  28. self.endorsed=False
  29. self.log = Logger(genesis_time)
  30. self.leader_id=None
  31. self.endorser_id=None
  32. def __repr__(self):
  33. if self.is_genesis:
  34. return "GensisBlock at {slot:"+str(self.sl)+",data:"+str(self.tx)+",state:"+str(self.state)+"}\n"+str(self.tx)
  35. return "Block at {slot:"+str(self.sl)+",data:"+str(self.tx)+",state:"+str(self.state)+"}"
  36. def __hash__(self):
  37. if type(self.tx)==str:
  38. return hash((self.state, self.tx, self.sl))
  39. elif type(self.tx)==dict:
  40. return hash((self.state, self.tx[SEED], self.tx[TX]))
  41. else:
  42. return hash(str(self))
  43. def __eq__(self, block):
  44. return self.state==block.state and \
  45. self.tx == block.tx and \
  46. self.sl == block.sl
  47. def to_json(self):
  48. d = {'state':self.state, \
  49. 'data': self.tx, \
  50. 'sl': self.sl}
  51. return json.encoder(d)
  52. def set_endorsed(self):
  53. self.endorsed=True
  54. def set_endorser(self, id):
  55. self.endorser_id=id
  56. self.set_endorsed()
  57. def set_leader(self, id):
  58. self.leader_id=id
  59. @property
  60. def data(self):
  61. return self.tx
  62. @property
  63. def slot(self):
  64. return self.sl
  65. @property
  66. def empty(self):
  67. return (self.tx=='' or self.slot<0) and self.state==''
  68. def encode(self):
  69. return str(self).encode()
  70. class GensisBlock(Block):
  71. '''
  72. @param data: data is dictionary of list of (pk_i, s_i) public key,
  73. and stake respectively of the corresponding stakeholder U_i,
  74. seed of the leader election function.
  75. '''
  76. def __init__(self, previous_block, data, slot_uid, genesis_time=time.time()):
  77. # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
  78. dist_block = data[0]
  79. self.stakeholders = dist_block[STAKEHOLDERS]
  80. self.distribution = dist_block[STAKEHOLDERS_DISTRIBUTIONS]
  81. self.seed = dist_block[SEED] #needed for pvss
  82. shd_buff = ''
  83. for shd in self.distribution:
  84. shd_buff +=str(shd)
  85. #data = encode_genesis_data(shd_buff)
  86. data_dict = {'seed':self.seed, 'distribution':shd_buff}
  87. Block.__init__(self, previous_block, str(data_dict), slot_uid, genesis_time, True)
  88. '''
  89. @return: the number of participating stakeholders in the blockchain
  90. '''
  91. @property
  92. def length(self):
  93. return len(self.stakeholders)
  94. def __getitem__(self, i):
  95. if i<0 or i>=self.length:
  96. raise "index is out of range!"
  97. return self.stakeholders[i]
  98. '''
  99. block lead by an adversary, or
  100. lead by offline leader
  101. is an empty Block
  102. '''
  103. class EmptyBlock(Block):
  104. def __init__(self, genesis_time=time.time()):
  105. Block.__init__(self, '', -1, genesis_time, False)