URI: 
       tcleanup storage and fix tracvis test - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 411832c4ce268cab388fac06c019a14940867dab
   DIR parent ee2e9f6092d5f173f5744176087dba20794edebe
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon,  6 Mar 2017 08:33:35 +0100
       
       cleanup storage and fix tracvis test
       
       Diffstat:
         M electrum                            |      11 +++++------
         M gui/qt/__init__.py                  |       3 +--
         M gui/qt/installwizard.py             |      15 +++++++--------
         M gui/stdio.py                        |       7 ++++---
         M gui/text.py                         |       5 +++--
         M lib/__init__.py                     |       3 ++-
         M lib/base_wizard.py                  |       2 +-
         M lib/daemon.py                       |       9 ++++-----
         M lib/storage.py                      |      77 ++++++++++++++-----------------
         M lib/wallet.py                       |       1 -
       
       10 files changed, 62 insertions(+), 71 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -124,7 +124,7 @@ def run_non_RPC(config):
            cmdname = config.get('cmd')
        
            storage = WalletStorage(config.get_wallet_path())
       -    if storage.file_exists:
       +    if storage.file_exists():
                sys.exit("Error: Remove the existing wallet first!")
        
            def password_dialog():
       t@@ -187,7 +187,7 @@ def run_non_RPC(config):
        def init_daemon(config_options):
            config = SimpleConfig(config_options)
            storage = WalletStorage(config.get_wallet_path())
       -    if not storage.file_exists:
       +    if not storage.file_exists():
                print_msg("Error: Wallet file not found.")
                print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
                sys.exit(0)
       t@@ -222,7 +222,7 @@ def init_cmdline(config_options, server):
            # instanciate wallet for command-line
            storage = WalletStorage(config.get_wallet_path())
        
       -    if cmd.requires_wallet and not storage.file_exists:
       +    if cmd.requires_wallet and not storage.file_exists():
                print_msg("Error: Wallet file not found.")
                print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
                sys.exit(0)
       t@@ -233,8 +233,6 @@ def init_cmdline(config_options, server):
                print_stderr("Exposing a single private key can compromise your entire wallet!")
                print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.")
        
       -    if not storage.is_encrypted():
       -        storage.read(None)
            # commands needing password
            if (cmd.requires_wallet and storage.is_encrypted() and server is None)\
               or (cmd.requires_password and (storage.get('use_encryption') or storage.is_encrypted())):
       t@@ -263,7 +261,8 @@ def run_offline_command(config, config_options):
            password = config_options.get('password')
            if cmd.requires_wallet:
                storage = WalletStorage(config.get_wallet_path())
       -        storage.read(password if storage.is_encrypted() else None)
       +        if storage.is_encrypted():
       +            storage.decrypt(password)
                wallet = Wallet(storage)
            else:
                wallet = None
   DIR diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py
       t@@ -162,13 +162,12 @@ class ElectrumGui:
                    wallet = self.daemon.get_wallet(path)
                    if not wallet:
                        storage = WalletStorage(path)
       -                if not storage.file_exists or storage.is_encrypted():
       +                if not storage.file_exists() or storage.is_encrypted():
                            wizard = InstallWizard(self.config, self.app, self.plugins, storage)
                            wallet = wizard.run_and_get_wallet()
                            if not wallet:
                                return
                        else:
       -                    storage.read(None)
                            wallet = Wallet(storage)
                        wallet.start_threads(self.daemon.network)
                        self.daemon.add_wallet(wallet)
   DIR diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -6,7 +6,7 @@ from PyQt4.QtCore import *
        import PyQt4.QtCore as QtCore
        
        import electrum
       -from electrum.wallet import Wallet, WalletStorage
       +from electrum import Wallet, WalletStorage
        from electrum.util import UserCancelled, InvalidPassword
        from electrum.base_wizard import BaseWizard
        from electrum.i18n import _
       t@@ -167,12 +167,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                    vbox.addLayout(hbox)
                    self.pw_e = None
        
       -            if not self.storage.file_exists:
       +            if not self.storage.file_exists():
                        msg = _("This file does not exist.") + '\n' \
                              + _("Press 'Next' to create this wallet, or chose another file.")
                        vbox.addWidget(QLabel(msg))
        
       -            elif self.storage.file_exists and self.storage.is_encrypted():
       +            elif self.storage.file_exists() and self.storage.is_encrypted():
                        msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.')
                        vbox.addWidget(QLabel(msg))
                        hbox2 = QHBoxLayout()
       t@@ -195,20 +195,19 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                while True:
                    update_layout()
        
       -            if self.storage.file_exists and not self.storage.is_encrypted():
       -                self.storage.read(None)
       +            if self.storage.file_exists() and not self.storage.is_encrypted():
                        break
        
                    if not self.loop.exec_():
                        return
        
       -            if not self.storage.file_exists:
       +            if not self.storage.file_exists():
                        break
        
       -            if self.storage.file_exists and self.storage.is_encrypted():
       +            if self.storage.file_exists() and self.storage.is_encrypted():
                        password = unicode(self.pw_e.text())
                        try:
       -                    self.storage.read(password)
       +                    self.storage.decrypt(password)
                            break
                        except InvalidPassword as e:
                            QMessageBox.information(None, _('Error'), str(e), _('OK'))
   DIR diff --git a/gui/stdio.py b/gui/stdio.py
       t@@ -1,7 +1,7 @@
        from decimal import Decimal
        _ = lambda x:x
        #from i18n import _
       -from electrum.wallet import WalletStorage, Wallet
       +from electrum import WalletStorage, Wallet
        from electrum.util import format_satoshis, set_verbosity, StoreDict
        from electrum.bitcoin import is_valid, COIN, TYPE_ADDRESS
        from electrum.network import filter_protocol
       t@@ -19,8 +19,9 @@ class ElectrumGui:
                if not storage.file_exists:
                    print "Wallet not found. try 'electrum create'"
                    exit()
       -        password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
       -        storage.read(password)
       +        if storage.is_encrypted():
       +            password = getpass.getpass('Password:', stream=None)
       +            storage.decrypt(password)
        
                self.done = 0
                self.last_balance = ""
   DIR diff --git a/gui/text.py b/gui/text.py
       t@@ -22,8 +22,9 @@ class ElectrumGui:
                if not storage.file_exists:
                    print "Wallet not found. try 'electrum create'"
                    exit()
       -        password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
       -        storage.read(password)
       +        if storage.is_encrypted():
       +            password = getpass.getpass('Password:', stream=None)
       +            storage.decrypt(password)
                self.wallet = Wallet(storage)
                self.wallet.start_threads(self.network)
                self.contacts = StoreDict(self.config, 'contacts')
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -1,6 +1,7 @@
        from version import ELECTRUM_VERSION
        from util import format_satoshis, print_msg, print_error, set_verbosity
       -from wallet import Synchronizer, WalletStorage, Wallet, Imported_Wallet
       +from wallet import Synchronizer, Wallet, Imported_Wallet
       +from storage import WalletStorage
        from coinchooser import COIN_CHOOSERS
        from network import Network, pick_random_server
        from interface import Connection, Interface
   DIR diff --git a/lib/base_wizard.py b/lib/base_wizard.py
       t@@ -26,7 +26,7 @@
        import os
        import bitcoin
        import keystore
       -from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, WalletStorage, wallet_types
       +from wallet import Wallet, Imported_Wallet, Standard_Wallet, Multisig_Wallet, wallet_types
        from i18n import _
        from plugins import run_hook
        
   DIR diff --git a/lib/daemon.py b/lib/daemon.py
       t@@ -35,7 +35,8 @@ from version import ELECTRUM_VERSION
        from network import Network
        from util import json_decode, DaemonThread
        from util import print_msg, print_error, print_stderr, UserCancelled
       -from wallet import WalletStorage, Wallet
       +from wallet import Wallet
       +from storage import WalletStorage
        from commands import known_commands, Commands
        from simple_config import SimpleConfig
        from plugins import run_hook
       t@@ -203,15 +204,13 @@ class Daemon(DaemonThread):
                    wallet = self.wallets[path]
                    return wallet
                storage = WalletStorage(path)
       -        if not storage.file_exists:
       +        if not storage.file_exists():
                    return
                if storage.is_encrypted():
                    password = password_getter()
                    if not password:
                        raise UserCancelled()
       -        else:
       -            password = None
       -        storage.read(password)
       +            storage.decrypt(password)
                if storage.requires_split():
                    return
                if storage.requires_upgrade():
   DIR diff --git a/lib/storage.py b/lib/storage.py
       t@@ -64,52 +64,19 @@ def multisig_type(wallet_type):
        class WalletStorage(PrintError):
        
            def __init__(self, path):
       +        self.print_error("wallet path", path)
                self.lock = threading.RLock()
                self.data = {}
                self.path = path
       -        self.file_exists = self.path and os.path.exists(self.path)
                self.modified = False
                self.pubkey = None
       -
       -    def decrypt(self, s, password):
       -        # Note: hardware wallets should use a seed-derived key and not require a password.
       -        # Thus, we need to expose keystore metadata
       -        if password is None:
       -            self.pubkey = None
       -            return s
       -        secret = pbkdf2.PBKDF2(password, '', iterations = 1024, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
       -        ec_key = bitcoin.EC_KEY(secret)
       -        self.pubkey = ec_key.get_public_key()
       -        return zlib.decompress(ec_key.decrypt_message(s)) if s else None
       -
       -    def set_password(self, pw, encrypt):
       -        """Set self.pubkey"""
       -        self.put('use_encryption', bool(pw))
       -        self.decrypt(None, pw if encrypt else None)
       -
       -    def is_encrypted(self):
       -        try:
       +        if self.file_exists():
                    with open(self.path, "r") as f:
       -                s = f.read(8)
       -        except IOError:
       -            return
       -        try:
       -            return base64.b64decode(s).startswith('BIE1')
       -        except:
       -            return False
       +                self.raw = f.read()
       +            if not self.is_encrypted():
       +                self.load_data(self.raw)
        
       -    def read(self, password):
       -        """Read the contents of the wallet file."""
       -        self.print_error("wallet path", self.path)
       -        try:
       -            with open(self.path, "r") as f:
       -                s = f.read()
       -        except IOError:
       -            return
       -        if not s:
       -            return
       -        # Decrypt wallet.
       -        s = self.decrypt(s, password)
       +    def load_data(self, s):
                try:
                    self.data = json.loads(s)
                except:
       t@@ -119,6 +86,33 @@ class WalletStorage(PrintError):
                l = plugin_loaders.get(t)
                if l: l()
        
       +    def is_encrypted(self):
       +        try:
       +            return base64.b64decode(self.raw).startswith('BIE1')
       +        except:
       +            return False
       +
       +    def file_exists(self):
       +        return self.path and os.path.exists(self.path)
       +
       +    def get_key(self, password):
       +        secret = pbkdf2.PBKDF2(password, '', iterations = 1024, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
       +        ec_key = bitcoin.EC_KEY(secret)
       +        return ec_key
       +
       +    def decrypt(self, password):
       +        ec_key = self.get_key(password)
       +        s = zlib.decompress(ec_key.decrypt_message(self.raw)) if self.raw else None
       +        self.load_data(s)
       +
       +    def set_password(self, password, encrypt):
       +        self.put('use_encryption', bool(password))
       +        if encrypt and password:
       +            ec_key = self.get_key(password)
       +            self.pubkey = ec_key.get_public_key()
       +        else:
       +            self.pubkey = None
       +
            def get(self, key, default=None):
                with self.lock:
                    v = self.data.get(key)
       t@@ -150,7 +144,6 @@ class WalletStorage(PrintError):
                self.put('seed_version', FINAL_SEED_VERSION)
                with self.lock:
                    self._write()
       -        self.file_exists = True
        
            def _write(self):
                if threading.currentThread().isDaemon():
       t@@ -230,7 +223,7 @@ class WalletStorage(PrintError):
                return result
        
            def requires_upgrade(self):
       -        return self.file_exists and self.get_seed_version() != FINAL_SEED_VERSION
       +        return self.file_exists() and self.get_seed_version() != FINAL_SEED_VERSION
        
            def upgrade(self):
                self.convert_imported()
       t@@ -371,7 +364,7 @@ class WalletStorage(PrintError):
                action = run_hook('get_action', self)
                if action:
                    return action
       -        if not self.file_exists:
       +        if not self.file_exists():
                    return 'new'
        
            def get_seed_version(self):
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -63,7 +63,6 @@ from mnemonic import Mnemonic
        
        import paymentrequest
        
       -from storage import WalletStorage
        
        TX_STATUS = [
            _('Replaceable'),