commit 411832c4ce268cab388fac06c019a14940867dab
parent ee2e9f6092d5f173f5744176087dba20794edebe
Author: ThomasV <thomasv@electrum.org>
Date: Mon, 6 Mar 2017 08:33:35 +0100
cleanup storage and fix tracvis test
Diffstat:
10 files changed, 62 insertions(+), 71 deletions(-)
diff --git a/electrum b/electrum
@@ -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():
@@ -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)
@@ -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)
@@ -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())):
@@ -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
diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py
@@ -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)
diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
@@ -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 _
@@ -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()
@@ -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'))
diff --git a/gui/stdio.py b/gui/stdio.py
@@ -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
@@ -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 = ""
diff --git a/gui/text.py b/gui/text.py
@@ -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')
diff --git a/lib/__init__.py b/lib/__init__.py
@@ -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
diff --git a/lib/base_wizard.py b/lib/base_wizard.py
@@ -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
diff --git a/lib/daemon.py b/lib/daemon.py
@@ -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
@@ -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():
diff --git a/lib/storage.py b/lib/storage.py
@@ -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:
@@ -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)
@@ -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():
@@ -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()
@@ -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):
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -63,7 +63,6 @@ from mnemonic import Mnemonic
import paymentrequest
-from storage import WalletStorage
TX_STATUS = [
_('Replaceable'),