mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
Previously the verifier job would scan all transactions in unverified_tx each time it ran. Nothing was ever removed from this map; it would essentially be the full set of transactions. As the job runs about 10 times a second, for a wallet with 500 txs this would be 5,000 useless loops a second. This patch makes unverified_tx be simply the set of confirmed transactions that haven't yet been verified. txs are added once confirmed, and removed once verified. Hence it will almost always be empty.
92 lines
3.6 KiB
Python
92 lines
3.6 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Electrum - lightweight Bitcoin client
|
|
# Copyright (C) 2012 thomasv@ecdsa.org
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
from util import ThreadJob
|
|
from functools import partial
|
|
from bitcoin import *
|
|
|
|
|
|
class SPV(ThreadJob):
|
|
""" Simple Payment Verification """
|
|
|
|
def __init__(self, network, wallet):
|
|
self.wallet = wallet
|
|
self.network = network
|
|
# Keyed by tx hash. Value is None if the merkle branch was
|
|
# requested, and the merkle root once it has been verified
|
|
self.merkle_roots = {}
|
|
|
|
def run(self):
|
|
lh = self.wallet.get_local_height()
|
|
unverified = self.wallet.get_unverified_txs()
|
|
for tx_hash, tx_height in unverified.items():
|
|
# do not request merkle branch before headers are available
|
|
if tx_hash not in self.merkle_roots and tx_height <= lh:
|
|
request = ('blockchain.transaction.get_merkle',
|
|
[tx_hash, tx_height])
|
|
if self.network.send([request], self.merkle_response):
|
|
self.print_error('requested merkle', tx_hash)
|
|
self.merkle_roots[tx_hash] = None
|
|
|
|
def merkle_response(self, r):
|
|
if r.get('error'):
|
|
self.print_error('received an error:', r)
|
|
return
|
|
|
|
params = r['params']
|
|
result = r['result']
|
|
|
|
# Get the header asynchronously - as a thread job we cannot block
|
|
tx_hash = params[0]
|
|
request = ('network.get_header',[result.get('block_height')])
|
|
self.network.send([request], partial(self.verify, tx_hash, result))
|
|
|
|
def verify(self, tx_hash, merkle, header):
|
|
'''Verify the hash of the server-provided merkle branch to a
|
|
transaction matches the merkle root of its block
|
|
'''
|
|
tx_height = merkle.get('block_height')
|
|
pos = merkle.get('pos')
|
|
merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos)
|
|
header = header.get('result')
|
|
if not header or header.get('merkle_root') != merkle_root:
|
|
# FIXME: we should make a fresh connection to a server to
|
|
# recover from this, as this TX will now never verify
|
|
self.print_error("merkle verification failed for", tx_hash)
|
|
return
|
|
|
|
# we passed all the tests
|
|
self.merkle_roots[tx_hash] = merkle_root
|
|
self.print_error("verified %s" % tx_hash)
|
|
self.wallet.add_verified_tx(tx_hash, (tx_height, header.get('timestamp'), pos))
|
|
|
|
|
|
def hash_merkle_root(self, merkle_s, target_hash, pos):
|
|
h = hash_decode(target_hash)
|
|
for i in range(len(merkle_s)):
|
|
item = merkle_s[i]
|
|
h = Hash( hash_decode(item) + h ) if ((pos >> i) & 1) else Hash( h + hash_decode(item) )
|
|
return hash_encode(h)
|
|
|
|
|
|
def undo_verifications(self, height):
|
|
tx_hashes = self.wallet.undo_verifications(height)
|
|
for tx_hash in tx_hashes:
|
|
self.print_error("redoing", tx_hash)
|
|
self.merkle_roots.pop(tx_hash, None)
|