block.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import json
  2. from ouroboros.utils import encode_genesis_data, decode_gensis_data, state_hash
  3. from ouroboros.consts import *
  4. '''
  5. single block B_i for slot i in the system live time L,
  6. assigned to stakeholder U_j, with propability P_j_i,
  7. in the chain C, should be signed by U_j keys.
  8. '''
  9. class Block(object):
  10. '''
  11. @param previous_block: parent block to the current block
  12. @param data: is the transaction, or contracts in the leadger, or gensis block data,
  13. data is expected to be binary, no format is enforced
  14. @param slot_uid: the block corresponding slot monotonically increasing index,
  15. it's one-based
  16. @param gensis: boolean, True for gensis block
  17. '''
  18. def __init__(self, previous_block, data, slot_uid, genesis=False):
  19. # state is hte hash of the previous block in the blockchain
  20. self.state=''
  21. if slot_uid>1:
  22. self.state=state_hash(previous_block)
  23. self.tx = data
  24. self.sl = slot_uid
  25. self.is_genesis=genesis
  26. def __repr__(self):
  27. if self.is_genesis:
  28. return "GensisBlock at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}\n"+\
  29. decode_gensis_data(self.data)
  30. return "Block at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}"
  31. def __hash__(self):
  32. if type(self.tx)==str:
  33. return hash((self.state, self.tx, self.sl))
  34. elif type(self.tx)==dict:
  35. #TODO include distribution
  36. return hash((self.state, self.tx[SEED], self.tx[TX]))
  37. else:
  38. #TODO (fix) shouldn't reach here
  39. return 0
  40. def __eq__(self, block):
  41. return self.state==block.state and \
  42. self.tx == block.tx and \
  43. self.sl == block.sl
  44. def to_json(self):
  45. d = {'state':self.state, \
  46. 'data': self.tx, \
  47. 'sl': self.sl}
  48. return json.encoder(d)
  49. @property
  50. def data(self):
  51. return self.tx
  52. @property
  53. def slot(self):
  54. return self.sl
  55. @property
  56. def empty(self):
  57. return (self.data=='' or self.slot<0) and self.state==''
  58. class GensisBlock(Block):
  59. '''
  60. @param data: data is dictionary of list of (pk_i, s_i) public key,
  61. and stake respectively of the corresponding stakeholder U_i,
  62. seed of the leader election function.
  63. '''
  64. def __init__(self, previous_block, data, slot_uid):
  65. # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
  66. self.stakeholders = data[STAKEHOLDERS]
  67. self.distribution = data[STAKEHOLDERS_DISTRIBUTIONS]
  68. self.seed = data.get(SEED, '') #needed for pvss
  69. shd_buff = ''
  70. for shd in self.distribution:
  71. shd_buff +=str(shd)
  72. #data = encode_genesis_data(shd_buff)
  73. data_dict = {'seed':self.seed, 'distribution':shd_buff}
  74. Block.__init__(self, previous_block, str(data_dict), slot_uid, True)
  75. '''
  76. @return: the number of participating stakeholders in the blockchain
  77. '''
  78. @property
  79. def length(self):
  80. return len(self.stakeholders)
  81. def __getitem__(self, i):
  82. if i<0 or i>=self.length:
  83. raise "index is out of range!"
  84. return self.stakeholders[i]
  85. '''
  86. block lead by an adversary, or
  87. lead by offline leader
  88. is an empty Block
  89. '''
  90. class EmptyBlock(Block):
  91. def __init__(self):
  92. Block.__init__(self, '', -1, False)