URI: 
       tWrite the wallet less often - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e1c0298fc29b171b1300076c7ec57fe5bf01707a
   DIR parent 0a3d74de8f2fa8eece37f4b728fb62a5b0658418
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Sun, 20 Dec 2015 15:39:57 +0900
       
       Write the wallet less often
       
       This should speed up synchronization / restoration of large wallets.
       Wallets are written only when they switch to up_to_date state, or
       when stop_threads() is called when closing the daemon, or when
       a command line command finishes.
       
       Diffstat:
         M electrum                            |      10 +++++++---
         M gui/gtk.py                          |       2 +-
         M gui/qt/installwizard.py             |       4 ++--
         M lib/synchronizer.py                 |       2 +-
         M lib/tests/test_wallet.py            |       2 +-
         M lib/util.py                         |       6 +++---
         M lib/wallet.py                       |      70 ++++++++++++++++----------------
         M plugins/labels/labels.py            |      10 +++++-----
         M plugins/trustedcoin/trustedcoin.py  |       4 ++--
       
       9 files changed, 57 insertions(+), 53 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -167,6 +167,7 @@ def init_cmdline(config):
                    print_msg("Your wallet generation seed is:\n\"%s\"" % seed)
                    print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.")
        
       +        wallet.storage.write()
                print_msg("Wallet saved in '%s'" % wallet.storage.path)
                sys.exit(0)
        
       t@@ -215,20 +216,22 @@ def init_cmdline(config):
                    if raw_input("Are you sure you want to continue? (y/n) ") in ['y', 'Y', 'yes']:
                        wallet.storage.path = ns
                        wallet.seed = ''
       -                wallet.storage.put('seed', '', True)
       +                wallet.storage.put('seed', '')
                        wallet.use_encryption = False
       -                wallet.storage.put('use_encryption', wallet.use_encryption, True)
       +                wallet.storage.put('use_encryption', wallet.use_encryption)
                        for k in wallet.imported_keys.keys():
                            wallet.imported_keys[k] = ''
       -                wallet.storage.put('imported_keys', wallet.imported_keys, True)
       +                wallet.storage.put('imported_keys', wallet.imported_keys)
                        print_msg("Done.")
                    else:
                        print_msg("Action canceled.")
       +        wallet.storage.write()
                sys.exit(0)
        
            elif cmd.name == 'password':
                new_password = prompt_password('New password:')
                wallet.update_password(password, new_password)
       +        wallet.storage.write()
                sys.exit(0)
        
            return cmd, password, wallet
       t@@ -320,6 +323,7 @@ if __name__ == '__main__':
                if not (cmd.requires_network or cmd.requires_wallet) or config.get('offline'):
                    result = run_offline_command(config, cmd, wallet, password)
                    print_msg(json_encode(result))
       +            wallet.storage.write()
                    sys.exit(0)
                else:
                    config_options['password'] = password
   DIR diff --git a/gui/gtk.py b/gui/gtk.py
       t@@ -1300,7 +1300,7 @@ class ElectrumGui():
                    gap = self.config.get('gap_limit', 5)
                    if gap != 5:
                        wallet.gap_limit = gap
       -                wallet.storage.put('gap_limit', gap, True)
       +                wallet.storage.put('gap_limit', gap)
        
                    if action == 'create':
                        seed = wallet.make_seed()
   DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -463,7 +463,7 @@ class InstallWizard(QDialog):
                    elif wallet_type == 'twofactor':
                        wallet_type = '2fa'
                    if action == 'create':
       -                self.storage.put('wallet_type', wallet_type, False)
       +                self.storage.put('wallet_type', wallet_type)
        
                if action is None:
                    return
       t@@ -560,7 +560,7 @@ class InstallWizard(QDialog):
                    password = self.password_dialog() if any(map(lambda x: Wallet.is_seed(x) or Wallet.is_xprv(x), key_list)) else None
                    wallet = Wallet.from_multisig(key_list, password, self.storage, t)
                else:
       -            self.storage.put('wallet_type', t, False)
       +            self.storage.put('wallet_type', t)
                    # call the constructor to load the plugin (side effect)
                    Wallet(self.storage)
                    wallet = always_hook('installwizard_restore', self, self.storage)
   DIR diff --git a/lib/synchronizer.py b/lib/synchronizer.py
       t@@ -179,5 +179,5 @@ class Synchronizer(ThreadJob):
                if up_to_date != self.wallet.is_up_to_date():
                    self.wallet.set_up_to_date(up_to_date)
                    if up_to_date:
       -                self.wallet.save_transactions()
       +                self.wallet.save_transactions(write=True)
                    self.network.trigger_callback('updated')
   DIR diff --git a/lib/tests/test_wallet.py b/lib/tests/test_wallet.py
       t@@ -57,7 +57,7 @@ class TestWalletStorage(WalletTestCase):
                some_dict = {"a":"b", "c":"d"}
        
                for key, value in some_dict.items():
       -            storage.put(key, value, False)
       +            storage.put(key, value)
                storage.write()
        
                contents = ""
   DIR diff --git a/lib/util.py b/lib/util.py
       t@@ -155,14 +155,14 @@ def json_decode(x):
        
        # decorator that prints execution time
        def profiler(func):
       -    def do_profile(func, args):
       +    def do_profile(func, args, kw_args):
                n = func.func_name
                t0 = time.time()
       -        o = apply(func, args)
       +        o = func(*args, **kw_args)
                t = time.time() - t0
                print_error("[profiler]", n, "%.4f"%t)
                return o
       -    return lambda *args: do_profile(func, args)
       +    return lambda *args, **kw_args: do_profile(func, args, kw_args)
        
        
        
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -98,7 +98,7 @@ class WalletStorage(PrintError):
                        v = copy.deepcopy(v)
                return v
        
       -    def put(self, key, value, save = True):
       +    def put(self, key, value):
                try:
                    json.dumps(key)
                    json.dumps(value)
       t@@ -113,8 +113,6 @@ class WalletStorage(PrintError):
                    elif key in self.data:
                        self.modified = True
                        self.data.pop(key)
       -            if save:
       -                self.write()
        
            def write(self):
                if threading.currentThread().isDaemon():
       t@@ -142,7 +140,7 @@ class WalletStorage(PrintError):
                    import stat
                    os.chmod(self.path, mode)
                self.print_error("saved", self.path)
       -
       +        self.modified = False
        
        
        class Abstract_Wallet(PrintError):
       t@@ -199,7 +197,7 @@ class Abstract_Wallet(PrintError):
        
                # save wallet type the first time
                if self.storage.get('wallet_type') is None:
       -            self.storage.put('wallet_type', self.wallet_type, True)
       +            self.storage.put('wallet_type', self.wallet_type)
        
            def diagnostic_name(self):
                return self.basename()
       t@@ -220,17 +218,18 @@ class Abstract_Wallet(PrintError):
                        self.transactions.pop(tx_hash)
        
            @profiler
       -    def save_transactions(self):
       +    def save_transactions(self, write=False):
                with self.transaction_lock:
                    tx = {}
                    for k,v in self.transactions.items():
                        tx[k] = str(v)
       -            # Flush storage only with the last put
       -            self.storage.put('transactions', tx, False)
       -            self.storage.put('txi', self.txi, False)
       -            self.storage.put('txo', self.txo, False)
       -            self.storage.put('pruned_txo', self.pruned_txo, False)
       -            self.storage.put('addr_history', self.history, True)
       +            self.storage.put('transactions', tx)
       +            self.storage.put('txi', self.txi)
       +            self.storage.put('txo', self.txo)
       +            self.storage.put('pruned_txo', self.pruned_txo)
       +            self.storage.put('addr_history', self.history)
       +            if write:
       +                self.storage.write()
        
            def clear_history(self):
                with self.transaction_lock:
       t@@ -376,7 +375,7 @@ class Abstract_Wallet(PrintError):
        
                if changed:
                    run_hook('set_label', self, name, text)
       -            self.storage.put('labels', self.labels, True)
       +            self.storage.put('labels', self.labels)
        
                return changed
        
       t@@ -436,7 +435,7 @@ class Abstract_Wallet(PrintError):
                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)
       +        self.storage.put('verified_tx3', self.verified_tx)
        
                conf, timestamp = self.get_confirmations(tx_hash)
                self.network.trigger_callback('verified', tx_hash, conf, timestamp)
       t@@ -1033,7 +1032,7 @@ class Abstract_Wallet(PrintError):
                if self.has_seed():
                    decoded = self.get_seed(old_password)
                    self.seed = pw_encode( decoded, new_password)
       -            self.storage.put('seed', self.seed, True)
       +            self.storage.put('seed', self.seed)
        
                imported_account = self.accounts.get(IMPORTED_ACCOUNT)
                if imported_account:
       t@@ -1045,10 +1044,10 @@ class Abstract_Wallet(PrintError):
                        b = pw_decode(v, old_password)
                        c = pw_encode(b, new_password)
                        self.master_private_keys[k] = c
       -            self.storage.put('master_private_keys', self.master_private_keys, True)
       +            self.storage.put('master_private_keys', self.master_private_keys)
        
                self.use_encryption = (new_password != None)
       -        self.storage.put('use_encryption', self.use_encryption,True)
       +        self.storage.put('use_encryption', self.use_encryption)
        
            def is_frozen(self, addr):
                return addr in self.frozen_addresses
       t@@ -1060,7 +1059,7 @@ class Abstract_Wallet(PrintError):
                        self.frozen_addresses |= set(addrs)
                    else:
                        self.frozen_addresses -= set(addrs)
       -            self.storage.put('frozen_addresses', list(self.frozen_addresses), True)
       +            self.storage.put('frozen_addresses', list(self.frozen_addresses))
                    return True
                return False
        
       t@@ -1098,7 +1097,8 @@ class Abstract_Wallet(PrintError):
                    self.verifier = None
                    # Now no references to the syncronizer or verifier
                    # remain so they will be GC-ed
       -            self.storage.put('stored_height', self.get_local_height(), True)
       +            self.storage.put('stored_height', self.get_local_height())
       +        self.storage.write()
        
            def wait_until_synchronized(self, callback=None):
                from i18n import _
       t@@ -1136,7 +1136,7 @@ class Abstract_Wallet(PrintError):
                d = {}
                for k, v in self.accounts.items():
                    d[k] = v.dump()
       -        self.storage.put('accounts', d, True)
       +        self.storage.put('accounts', d)
        
            def can_import(self):
                return not self.is_watching_only()
       t@@ -1420,9 +1420,9 @@ class Deterministic_Wallet(Abstract_Wallet):
                else:
                    self.use_encryption = False
        
       -        self.storage.put('seed', self.seed, False)
       -        self.storage.put('seed_version', self.seed_version, False)
       -        self.storage.put('use_encryption', self.use_encryption,True)
       +        self.storage.put('seed', self.seed)
       +        self.storage.put('seed_version', self.seed_version)
       +        self.storage.put('use_encryption', self.use_encryption)
        
            def get_seed(self, password):
                return pw_decode(self.seed, password)
       t@@ -1434,7 +1434,7 @@ class Deterministic_Wallet(Abstract_Wallet):
                assert isinstance(value, int), 'gap limit must be of type int, not of %s'%type(value)
                if value >= self.gap_limit:
                    self.gap_limit = value
       -            self.storage.put('gap_limit', self.gap_limit, True)
       +            self.storage.put('gap_limit', self.gap_limit)
                    return True
        
                elif value >= self.min_acceptable_gap():
       t@@ -1445,7 +1445,7 @@ class Deterministic_Wallet(Abstract_Wallet):
                        account.receiving_pubkeys = account.receiving_pubkeys[0:n]
                        account.receiving_addresses = account.receiving_addresses[0:n]
                    self.gap_limit = value
       -            self.storage.put('gap_limit', self.gap_limit, True)
       +            self.storage.put('gap_limit', self.gap_limit)
                    self.save_accounts()
                    return True
                else:
       t@@ -1568,11 +1568,11 @@ class BIP32_Wallet(Deterministic_Wallet):
                if xpub in self.master_public_keys.values():
                    raise BaseException('Duplicate master public key')
                self.master_public_keys[name] = xpub
       -        self.storage.put('master_public_keys', self.master_public_keys, True)
       +        self.storage.put('master_public_keys', self.master_public_keys)
        
            def add_master_private_key(self, name, xpriv, password):
                self.master_private_keys[name] = pw_encode(xpriv, password)
       -        self.storage.put('master_private_keys', self.master_private_keys, True)
       +        self.storage.put('master_private_keys', self.master_private_keys)
        
            def derive_xkeys(self, root, derivation, password):
                x = self.master_private_keys[root]
       t@@ -1615,16 +1615,16 @@ class BIP32_Simple_Wallet(BIP32_Wallet):
            def create_xprv_wallet(self, xprv, password):
                xpub = bitcoin.xpub_from_xprv(xprv)
                account = BIP32_Account({'xpub':xpub})
       -        self.storage.put('seed_version', self.seed_version, True)
       +        self.storage.put('seed_version', self.seed_version)
                self.add_master_private_key(self.root_name, xprv, password)
                self.add_master_public_key(self.root_name, xpub)
                self.add_account('0', account)
                self.use_encryption = (password != None)
       -        self.storage.put('use_encryption', self.use_encryption,True)
       +        self.storage.put('use_encryption', self.use_encryption)
        
            def create_xpub_wallet(self, xpub):
                account = BIP32_Account({'xpub':xpub})
       -        self.storage.put('seed_version', self.seed_version, True)
       +        self.storage.put('seed_version', self.seed_version)
                self.add_master_public_key(self.root_name, xpub)
                self.add_account('0', account)
        
       t@@ -1823,7 +1823,7 @@ class OldWallet(Deterministic_Wallet):
            def create_master_keys(self, password):
                seed = self.get_seed(password)
                mpk = OldAccount.mpk_from_seed(seed)
       -        self.storage.put('master_public_key', mpk, True)
       +        self.storage.put('master_public_key', mpk)
        
            def get_master_public_key(self):
                return self.storage.get("master_public_key")
       t@@ -1841,8 +1841,8 @@ class OldWallet(Deterministic_Wallet):
        
            def create_watching_only_wallet(self, mpk):
                self.seed_version = OLD_SEED_VERSION
       -        self.storage.put('seed_version', self.seed_version, False)
       -        self.storage.put('master_public_key', mpk, True)
       +        self.storage.put('seed_version', self.seed_version)
       +        self.storage.put('master_public_key', mpk)
                self.create_account(mpk)
        
            def get_seed(self, password):
       t@@ -2026,7 +2026,7 @@ class Wallet(object):
        
            @classmethod
            def from_multisig(klass, key_list, password, storage, wallet_type):
       -        storage.put('wallet_type', wallet_type, True)
       +        storage.put('wallet_type', wallet_type)
                self = Multisig_Wallet(storage)
                key_list = sorted(key_list, key = lambda x: klass.is_xpub(x))
                for i, text in enumerate(key_list):
       t@@ -2045,7 +2045,7 @@ class Wallet(object):
                        else:
                            self.add_cosigner_seed(text, name, password)
                self.use_encryption = (password != None)
       -        self.storage.put('use_encryption', self.use_encryption, True)
       +        self.storage.put('use_encryption', self.use_encryption)
                self.create_main_account(password)
                return self
        
   DIR diff --git a/plugins/labels/labels.py b/plugins/labels/labels.py
       t@@ -42,9 +42,9 @@ class LabelsPlugin(BasePlugin):
                    self.set_nonce(wallet, nonce)
                return nonce
        
       -    def set_nonce(self, wallet, nonce, force_write=True):
       +    def set_nonce(self, wallet, nonce):
                self.print_error("set", wallet.basename(), "nonce to", nonce)
       -        wallet.storage.put("wallet_nonce", nonce, force_write)
       +        wallet.storage.put("wallet_nonce", nonce)
        
            @hook
            def set_label(self, wallet, item, label):
       t@@ -61,7 +61,7 @@ class LabelsPlugin(BasePlugin):
                t.setDaemon(True)
                t.start()
                # Caller will write the wallet
       -        self.set_nonce(wallet, nonce + 1, force_write=False)
       +        self.set_nonce(wallet, nonce + 1)
        
            def do_request(self, method, url = "/labels", is_batch=False, data=None):
                url = 'https://' + self.target_host + url
       t@@ -125,8 +125,8 @@ class LabelsPlugin(BasePlugin):
        
                    self.print_error("received %d labels" % len(response))
                    # do not write to disk because we're in a daemon thread
       -            wallet.storage.put('labels', wallet.labels, False)
       -            self.set_nonce(wallet, response["nonce"] + 1, False)
       +            wallet.storage.put('labels', wallet.labels)
       +            self.set_nonce(wallet, response["nonce"] + 1)
                    self.on_pulled(wallet)
        
                except Exception as e:
   DIR diff --git a/plugins/trustedcoin/trustedcoin.py b/plugins/trustedcoin/trustedcoin.py
       t@@ -305,8 +305,8 @@ class TrustedCoinPlugin(BasePlugin):
                    return
        
                password = window.password_dialog()
       -        wallet.storage.put('seed_version', wallet.seed_version, True)
       -        wallet.storage.put('use_encryption', password is not None, True)
       +        wallet.storage.put('seed_version', wallet.seed_version)
       +        wallet.storage.put('use_encryption', password is not None)
        
                words = seed.split()
                n = len(words)/2