blockchain.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. class Blockchain:
  2. def __init__(self, blocks: list):
  3. self.blocks = blocks
  4. assert self.blocks[0].height == 0
  5. self.block_indices = {block.hash: i for (i, block) in enumerate(blocks)}
  6. def get_transaction_by_hash(self, hash_val: bytes):
  7. """
  8. Returns a transaction from its hash, or None.
  9. """
  10. # TODO: build a hash table with this info
  11. for block in self.blocks[::-1]:
  12. for trans in block.transactions:
  13. if trans.get_hash() == hash_val:
  14. return trans
  15. return None
  16. def is_coin_still_valid(self, transaction_input, prev_block=None):
  17. """
  18. Validates that the coins that were sent in the transaction identified
  19. by `transaction_hash_val` to the nth receiver (n=output_idx) have not been
  20. spent before the given block.
  21. """
  22. if prev_block is None:
  23. prev_block = self.head
  24. idx = self.block_indices[prev_block.hash]
  25. assert self.blocks[idx] is prev_block
  26. for block in self.blocks[idx::-1]:
  27. for trans in block.transactions:
  28. if transaction_input in trans.inputs:
  29. return False
  30. return True
  31. def get_block_by_hash(self, hash_val):
  32. """
  33. Returns a block by its hash value, or None if it cannot be found.
  34. """
  35. return self.blocks[self.block_indices.get(hash_val)]
  36. def verify_all_transactions(self):
  37. """
  38. Verify the transactions in all blocks in this chain.
  39. """
  40. for block in self.blocks:
  41. if not block.verify_transactions(self):
  42. return False
  43. return True
  44. @property
  45. def head(self):
  46. """ The head of this block chain. """
  47. return self.blocks[-1]
  48. def compute_difficulty(self):
  49. """ Compute the desired difficulty for the next block. """
  50. # TODO: dynamic calculation
  51. # TODO: verify difficulty in new blocks
  52. return self.head.difficulty
  53. def compute_blockreward(self, prev_block):
  54. assert prev_block is not None
  55. reward = 1000
  56. l = self.block_indices[prev_block.hash]
  57. while l > 0:
  58. l = l - 10000
  59. reward = reward // 2
  60. return reward