commit 351272f0b6f8f253483ea6913fcc8c5932a16378
parent 478bde8afab6c8670103126245ab49e5977f1b1e
Author: Neil Booth <kyuupichan@gmail.com>
Date: Fri, 28 Aug 2015 12:39:19 +0900
Small optimization for large wallets
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.
Diffstat:
2 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/lib/verifier.py b/lib/verifier.py
@@ -33,9 +33,11 @@ class SPV(ThreadJob):
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:
- if tx_hash not in self.merkle_roots:
+ 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):
@@ -64,6 +66,8 @@ class SPV(ThreadJob):
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
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -417,10 +417,13 @@ class Abstract_Wallet(object):
return decrypted
def add_unverified_tx(self, tx_hash, tx_height):
- if tx_height > 0:
+ # Only add if confirmed and not verified
+ if tx_height > 0 and tx_hash not in self.verified_tx:
self.unverified_tx[tx_hash] = tx_height
def add_verified_tx(self, tx_hash, info):
+ # Remove from the unverified map and add to the verified map and
+ self.unverified_tx.pop(tx_hash, None)
with self.lock:
self.verified_tx[tx_hash] = info # (tx_height, timestamp, pos)
self.storage.put('verified_tx3', self.verified_tx, True)
@@ -429,14 +432,8 @@ class Abstract_Wallet(object):
self.network.trigger_callback('verified', (tx_hash, conf, timestamp))
def get_unverified_txs(self):
- '''Returns a list of tuples (tx_hash, height) that are unverified
- and not beyond local height'''
- txs = []
- for tx_hash, tx_height in self.unverified_tx.items():
- # do not request merkle branch before headers are available
- if tx_hash not in self.verified_tx and tx_height <= self.get_local_height():
- txs.append((tx_hash, tx_height))
- return txs
+ '''Returns a map from tx hash to transaction height'''
+ return self.unverified_tx
def undo_verifications(self, height):
'''Used by the verifier when a reorg has happened'''