electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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:
Mlib/verifier.py | 8++++++--
Mlib/wallet.py | 15++++++---------
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'''