class WalletVerifier(threading.Thread):
+ """ Simple Verification Protocol """
- def __init__(self, interface, config, get_transactions):
+ def __init__(self, interface, config):
threading.Thread.__init__(self)
self.daemon = True
self.config = config
self.interface = interface
- self.get_transactions = get_transactions
+ self.transactions = [] # monitored transactions
self.interface.register_channel('verifier')
- self.verified_tx = config.get('verified_tx',[])
+ self.verified_tx = config.get('verified_tx',{})
self.merkle_roots = config.get('merkle_roots',{}) # hashed by me
self.targets = config.get('targets',{}) # compute targets
self.lock = threading.Lock()
self.pending_headers = [] # headers that have not been verified
self.height = 0
self.local_height = 0
- self.set_local_numblocks()
+ self.set_local_height()
+ def get_confirmations(self, tx):
+ """ return the number of confirmations of a monitored transaction. """
+ with self.lock:
+ assert tx in self.transactions
+ return (self.local_height - self.verified_tx[tx] + 1) if tx in self.verified_tx else 0
-
+ def add(self, tx):
+ """ add a transaction to the list of monitored transactions. """
+ with self.lock:
+ if tx not in self.transactions:
+ self.transactions.append(tx)
def run(self):
requested_merkle = []
requested_chunks = []
requested_headers = []
+ pending_headers_changed = False
# subscribe to block headers
self.interface.send([ ('blockchain.headers.subscribe',[])], 'verifier')
requested_headers.append(i)
# request missing tx merkle
- txlist = self.get_transactions()
- for tx in txlist:
+ for tx in self.transactions:
if tx not in self.verified_tx:
if tx not in requested_merkle:
requested_merkle.append(tx)
elif method == 'blockchain.headers.subscribe':
self.height = result.get('block_height')
self.pending_headers.append(result)
+ pending_headers_changed = True
elif method == 'blockchain.block.get_header':
height = result.get('block_height')
requested_headers.remove(height)
self.pending_headers.append(result)
+ pending_headers_changed = True
# process pending headers
- # todo: sort them first
- for header in self.pending_headers:
- self.verify_header(header)
- self.pending_headers = []
+ if pending_headers_changed:
+ self.pending_headers.sort(key=lambda x: x.get('block_height'))
+ print "pending headers", map(lambda x: x.get('block_height'), self.pending_headers)
+ for header in self.pending_headers:
+ if self.verify_header(header):
+ self.pending_headers.remove(header)
+ else:
+ break
+ pending_headers_changed = False
+ self.interface.trigger_callback('updated')
def request_merkle(self, tx_hash):
header = self.read_header(tx_height)
if header:
assert header.get('merkle_root') == self.merkle_roots[tx_hash]
- self.verified_tx.append(tx_hash)
+ self.verified_tx[tx_hash] = tx_height
print "verified", tx_hash
self.config.set_key('verified_tx', self.verified_tx, True)
prev_header = self.read_header(height -1)
if not prev_header:
- raise "no previous header", height
+ print "no previous header", height
return
#prev_hash = prev_header.get('block_height')
if ok:
self.save_header(header)
print "verify header: ok", height
+ return True
f.seek(index*2016*80)
h = f.write(chunk)
f.close()
- self.set_local_numblocks()
+ self.set_local_height()
def save_header(self, header):
data = self.header_to_string(header).decode('hex')
f.seek(height*80)
h = f.write(data)
f.close()
- self.set_local_numblocks()
+ self.set_local_height()
+
- def set_local_numblocks(self):
+ def set_local_height(self):
name = self.path()
if os.path.exists(name):
- self.local_height = os.path.getsize(name)/80 - 1
- # print "local height", self.local_height, os.path.getsize(name)/80.
+ h = os.path.getsize(name)/80 - 1
+ if self.local_height != h:
+ self.local_height = h
def read_header(self, block_height):