1
0

simple payment verification: check targets, use block headers file.

This commit is contained in:
ThomasV
2012-10-24 21:45:45 +02:00
parent e5c19b64af
commit b018e0ae53
6 changed files with 275 additions and 122 deletions

View File

@@ -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)