simple payment verification: check targets, use block headers file.
This commit is contained in:
116
lib/wallet.py
116
lib/wallet.py
@@ -940,119 +940,3 @@ class WalletSynchronizer(threading.Thread):
|
||||
self.wallet.was_updated = False
|
||||
|
||||
|
||||
encode = lambda x: x[::-1].encode('hex')
|
||||
decode = lambda x: x.decode('hex')[::-1]
|
||||
from bitcoin import Hash, rev_hex, int_to_hex
|
||||
|
||||
class WalletVerifier(threading.Thread):
|
||||
|
||||
def __init__(self, wallet, config):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.config = config
|
||||
self.wallet = wallet
|
||||
self.interface = self.wallet.interface
|
||||
self.interface.register_channel('verifier')
|
||||
self.validated = config.get('verified_tx',[])
|
||||
self.merkle_roots = config.get('merkle_roots',{})
|
||||
self.headers = config.get('block_headers',{})
|
||||
self.lock = threading.Lock()
|
||||
self.saved = True
|
||||
|
||||
def run(self):
|
||||
requested = []
|
||||
|
||||
while True:
|
||||
txlist = self.wallet.get_tx_hashes()
|
||||
|
||||
for tx in txlist:
|
||||
if tx not in self.validated:
|
||||
if tx not in requested:
|
||||
requested.append(tx)
|
||||
self.request_merkle(tx)
|
||||
self.saved = False
|
||||
break
|
||||
|
||||
try:
|
||||
r = self.interface.get_response('verifier',timeout=1)
|
||||
except Queue.Empty:
|
||||
if len(self.validated) == len(txlist) and not self.saved:
|
||||
print "saving verified transactions"
|
||||
self.config.set_key('verified_tx', self.validated, True)
|
||||
self.saved = True
|
||||
continue
|
||||
|
||||
# 3. handle response
|
||||
method = r['method']
|
||||
params = r['params']
|
||||
result = r['result']
|
||||
|
||||
if method == 'blockchain.transaction.get_merkle':
|
||||
tx_hash = params[0]
|
||||
tx_height = result.get('block_height')
|
||||
self.merkle_roots[tx_hash] = self.hash_merkle_root(result['merkle'], tx_hash)
|
||||
# if we already have the header, check merkle root directly
|
||||
header = self.headers.get(tx_height)
|
||||
if header:
|
||||
self.validated.append(tx_hash)
|
||||
assert header.get('merkle_root') == self.merkle_roots[tx_hash]
|
||||
self.request_headers(tx_height)
|
||||
|
||||
elif method == 'blockchain.block.get_header':
|
||||
self.validate_header(result)
|
||||
|
||||
|
||||
def request_merkle(self, tx_hash):
|
||||
self.interface.send([ ('blockchain.transaction.get_merkle',[tx_hash]) ], 'verifier')
|
||||
|
||||
|
||||
def request_headers(self, tx_height, delta=10):
|
||||
headers_requests = []
|
||||
for height in range(tx_height-delta,tx_height+delta): # we might can request blocks that do not exist yet
|
||||
if height not in self.headers:
|
||||
headers_requests.append( ('blockchain.block.get_header',[height]) )
|
||||
self.interface.send(headers_requests,'verifier')
|
||||
|
||||
|
||||
def validate_header(self, header):
|
||||
""" if there is a previous or a next block in the list, check the hash"""
|
||||
height = header.get('block_height')
|
||||
with self.lock:
|
||||
self.headers[height] = header # detect conflicts
|
||||
prev_header = next_header = None
|
||||
if height-1 in self.headers:
|
||||
prev_header = self.headers[height-1]
|
||||
if height+1 in self.headers:
|
||||
next_header = self.headers[height+1]
|
||||
|
||||
if prev_header:
|
||||
prev_hash = self.hash_header(prev_header)
|
||||
assert prev_hash == header.get('prev_block_hash')
|
||||
if next_header:
|
||||
_hash = self.hash_header(header)
|
||||
assert _hash == next_header.get('prev_block_hash')
|
||||
|
||||
# check if there are transactions at that height
|
||||
for tx_hash in self.wallet.get_transactions_at_height(height):
|
||||
if tx_hash in self.validated: continue
|
||||
# check if we already have the merkle root
|
||||
merkle_root = self.merkle_roots.get(tx_hash)
|
||||
if merkle_root:
|
||||
self.validated.append(tx_hash)
|
||||
assert header.get('merkle_root') == merkle_root
|
||||
|
||||
def hash_header(self, res):
|
||||
header = int_to_hex(res.get('version'),4) \
|
||||
+ rev_hex(res.get('prev_block_hash')) \
|
||||
+ rev_hex(res.get('merkle_root')) \
|
||||
+ int_to_hex(int(res.get('timestamp')),4) \
|
||||
+ int_to_hex(int(res.get('bits')),4) \
|
||||
+ int_to_hex(int(res.get('nonce')),4)
|
||||
return rev_hex(Hash(header.decode('hex')).encode('hex'))
|
||||
|
||||
def hash_merkle_root(self, merkle_s, target_hash):
|
||||
h = decode(target_hash)
|
||||
for item in merkle_s:
|
||||
is_left = item[0] == 'L'
|
||||
h = Hash( h + decode(item[1:]) ) if is_left else Hash( decode(item[1:]) + h )
|
||||
return encode(h)
|
||||
|
||||
Reference in New Issue
Block a user