verifier.py 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env python
  2. #
  3. # Electrum - Lightweight Bitcoin Client
  4. # Copyright (c) 2012 Thomas Voegtlin
  5. #
  6. # Permission is hereby granted, free of charge, to any person
  7. # obtaining a copy of this software and associated documentation files
  8. # (the "Software"), to deal in the Software without restriction,
  9. # including without limitation the rights to use, copy, modify, merge,
  10. # publish, distribute, sublicense, and/or sell copies of the Software,
  11. # and to permit persons to whom the Software is furnished to do so,
  12. # subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be
  15. # included in all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  21. # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  22. # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. # SOFTWARE.
  25. from util import ThreadJob
  26. from bitcoin import *
  27. class SPV(ThreadJob):
  28. """ Simple Payment Verification """
  29. def __init__(self, network, wallet):
  30. self.wallet = wallet
  31. self.network = network
  32. # Keyed by tx hash. Value is None if the merkle branch was
  33. # requested, and the merkle root once it has been verified
  34. self.merkle_roots = {}
  35. def run(self):
  36. lh = self.network.get_local_height()
  37. unverified = self.wallet.get_unverified_txs()
  38. for tx_hash, tx_height in unverified.items():
  39. # do not request merkle branch before headers are available
  40. if tx_hash not in self.merkle_roots and tx_height <= lh:
  41. request = ('blockchain.transaction.get_merkle',
  42. [tx_hash, tx_height])
  43. self.network.send([request], self.verify_merkle)
  44. self.print_error('requested merkle', tx_hash)
  45. self.merkle_roots[tx_hash] = None
  46. def verify_merkle(self, r):
  47. if r.get('error'):
  48. self.print_error('received an error:', r)
  49. return
  50. params = r['params']
  51. merkle = r['result']
  52. # Verify the hash of the server-provided merkle branch to a
  53. # transaction matches the merkle root of its block
  54. tx_hash = params[0]
  55. tx_height = merkle.get('block_height')
  56. pos = merkle.get('pos')
  57. merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos)
  58. header = self.network.get_header(tx_height)
  59. if not header or header.get('merkle_root') != merkle_root:
  60. # FIXME: we should make a fresh connection to a server to
  61. # recover from this, as this TX will now never verify
  62. self.print_error("merkle verification failed for", tx_hash)
  63. return
  64. # we passed all the tests
  65. self.merkle_roots[tx_hash] = merkle_root
  66. self.print_error("verified %s" % tx_hash)
  67. self.wallet.add_verified_tx(tx_hash, (tx_height, header.get('timestamp'), pos))
  68. def hash_merkle_root(self, merkle_s, target_hash, pos):
  69. h = hash_decode(target_hash)
  70. for i in range(len(merkle_s)):
  71. item = merkle_s[i]
  72. h = Hash( hash_decode(item) + h ) if ((pos >> i) & 1) else Hash( h + hash_decode(item) )
  73. return hash_encode(h)
  74. def undo_verifications(self, height):
  75. tx_hashes = self.wallet.undo_verifications(height)
  76. for tx_hash in tx_hashes:
  77. self.print_error("redoing", tx_hash)
  78. self.merkle_roots.pop(tx_hash, None)