transaction.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. from collections import namedtuple
  2. from crypto import get_hasher, sign, verify_sign
  3. """ The recipient of a transaction ('coin'). """
  4. TransactionTarget = namedtuple("TransactionTarget", ["recipient_pk", "amount"])
  5. """ One transaction input (pointer to 'coin'). """
  6. TransactionInput = namedtuple("TransactionInput", ["transaction_hash", "output_idx"])
  7. class Transaction:
  8. def __init__(self, inputs, targets, signatures=None):
  9. self.inputs = inputs
  10. self.targets = targets
  11. self.signatures = signatures or []
  12. def get_hash(self):
  13. """ Hash this transaction. Returns raw bytes. """
  14. h = get_hasher()
  15. for target in self.targets:
  16. h.update(target.amount)
  17. h.update(target.recipient_pk)
  18. for inp in self.inputs:
  19. h.update(inp)
  20. return h.digest()
  21. def sign(self, private_key):
  22. """ Sign this transaction with a private key. You need to call this in the same order as the inputs. """
  23. self.signatures.append(sign(self.get_hash(), private_key))
  24. def _verify_signatures(self, chain):
  25. """ Verify that all inputs are signed and the signatures are valid. """
  26. if len(self.signatures) != len(self.inputs)
  27. return False
  28. for (s, i) in zip(self.signatures, self.inputs):
  29. if not self._verify_single_sig(s, i, chain):
  30. return False
  31. return True
  32. def _verify_single_sig(self, sig, inp, chain):
  33. """ Verifies the signature on a single input. """
  34. trans = chain.get_transaction_by_hash(inp.transaction_hash)
  35. sender_pk = trans.targets[inp.output_idx]
  36. return verify_sign(self.get_hash(), sig)
  37. def _verify_single_spend(self, chain, prev_block):
  38. """ Verifies that all inputs have not been spent yet. """
  39. for i in self.inputs:
  40. if not chain.is_coin_still_valid(i, prev_block):
  41. return False
  42. return True
  43. def verify(self, chain, prev_block=None):
  44. """ Verifies that this transaction is completely valid. """
  45. return self._verify_single_spend(chain, prev_block) and self._verify_signatures(chain)