cleanup storage and fix tracvis test
This commit is contained in:
11
electrum
11
electrum
@@ -124,7 +124,7 @@ def run_non_RPC(config):
|
|||||||
cmdname = config.get('cmd')
|
cmdname = config.get('cmd')
|
||||||
|
|
||||||
storage = WalletStorage(config.get_wallet_path())
|
storage = WalletStorage(config.get_wallet_path())
|
||||||
if storage.file_exists:
|
if storage.file_exists():
|
||||||
sys.exit("Error: Remove the existing wallet first!")
|
sys.exit("Error: Remove the existing wallet first!")
|
||||||
|
|
||||||
def password_dialog():
|
def password_dialog():
|
||||||
@@ -187,7 +187,7 @@ def run_non_RPC(config):
|
|||||||
def init_daemon(config_options):
|
def init_daemon(config_options):
|
||||||
config = SimpleConfig(config_options)
|
config = SimpleConfig(config_options)
|
||||||
storage = WalletStorage(config.get_wallet_path())
|
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("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")
|
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -222,7 +222,7 @@ def init_cmdline(config_options, server):
|
|||||||
# instanciate wallet for command-line
|
# instanciate wallet for command-line
|
||||||
storage = WalletStorage(config.get_wallet_path())
|
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("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")
|
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
|
||||||
sys.exit(0)
|
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("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.")
|
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
|
# commands needing password
|
||||||
if (cmd.requires_wallet and storage.is_encrypted() and server is None)\
|
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())):
|
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')
|
password = config_options.get('password')
|
||||||
if cmd.requires_wallet:
|
if cmd.requires_wallet:
|
||||||
storage = WalletStorage(config.get_wallet_path())
|
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)
|
wallet = Wallet(storage)
|
||||||
else:
|
else:
|
||||||
wallet = None
|
wallet = None
|
||||||
|
|||||||
@@ -162,13 +162,12 @@ class ElectrumGui:
|
|||||||
wallet = self.daemon.get_wallet(path)
|
wallet = self.daemon.get_wallet(path)
|
||||||
if not wallet:
|
if not wallet:
|
||||||
storage = WalletStorage(path)
|
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)
|
wizard = InstallWizard(self.config, self.app, self.plugins, storage)
|
||||||
wallet = wizard.run_and_get_wallet()
|
wallet = wizard.run_and_get_wallet()
|
||||||
if not wallet:
|
if not wallet:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
storage.read(None)
|
|
||||||
wallet = Wallet(storage)
|
wallet = Wallet(storage)
|
||||||
wallet.start_threads(self.daemon.network)
|
wallet.start_threads(self.daemon.network)
|
||||||
self.daemon.add_wallet(wallet)
|
self.daemon.add_wallet(wallet)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from PyQt4.QtCore import *
|
|||||||
import PyQt4.QtCore as QtCore
|
import PyQt4.QtCore as QtCore
|
||||||
|
|
||||||
import electrum
|
import electrum
|
||||||
from electrum.wallet import Wallet, WalletStorage
|
from electrum import Wallet, WalletStorage
|
||||||
from electrum.util import UserCancelled, InvalidPassword
|
from electrum.util import UserCancelled, InvalidPassword
|
||||||
from electrum.base_wizard import BaseWizard
|
from electrum.base_wizard import BaseWizard
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
@@ -167,12 +167,12 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
vbox.addLayout(hbox)
|
vbox.addLayout(hbox)
|
||||||
self.pw_e = None
|
self.pw_e = None
|
||||||
|
|
||||||
if not self.storage.file_exists:
|
if not self.storage.file_exists():
|
||||||
msg = _("This file does not exist.") + '\n' \
|
msg = _("This file does not exist.") + '\n' \
|
||||||
+ _("Press 'Next' to create this wallet, or chose another file.")
|
+ _("Press 'Next' to create this wallet, or chose another file.")
|
||||||
vbox.addWidget(QLabel(msg))
|
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.')
|
msg = _("This file is encrypted.") + '\n' + _('Enter your password or choose another file.')
|
||||||
vbox.addWidget(QLabel(msg))
|
vbox.addWidget(QLabel(msg))
|
||||||
hbox2 = QHBoxLayout()
|
hbox2 = QHBoxLayout()
|
||||||
@@ -195,20 +195,19 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
while True:
|
while True:
|
||||||
update_layout()
|
update_layout()
|
||||||
|
|
||||||
if self.storage.file_exists and not self.storage.is_encrypted():
|
if self.storage.file_exists() and not self.storage.is_encrypted():
|
||||||
self.storage.read(None)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if not self.loop.exec_():
|
if not self.loop.exec_():
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.storage.file_exists:
|
if not self.storage.file_exists():
|
||||||
break
|
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())
|
password = unicode(self.pw_e.text())
|
||||||
try:
|
try:
|
||||||
self.storage.read(password)
|
self.storage.decrypt(password)
|
||||||
break
|
break
|
||||||
except InvalidPassword as e:
|
except InvalidPassword as e:
|
||||||
QMessageBox.information(None, _('Error'), str(e), _('OK'))
|
QMessageBox.information(None, _('Error'), str(e), _('OK'))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
_ = lambda x:x
|
_ = lambda x:x
|
||||||
#from i18n import _
|
#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.util import format_satoshis, set_verbosity, StoreDict
|
||||||
from electrum.bitcoin import is_valid, COIN, TYPE_ADDRESS
|
from electrum.bitcoin import is_valid, COIN, TYPE_ADDRESS
|
||||||
from electrum.network import filter_protocol
|
from electrum.network import filter_protocol
|
||||||
@@ -19,8 +19,9 @@ class ElectrumGui:
|
|||||||
if not storage.file_exists:
|
if not storage.file_exists:
|
||||||
print "Wallet not found. try 'electrum create'"
|
print "Wallet not found. try 'electrum create'"
|
||||||
exit()
|
exit()
|
||||||
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
|
if storage.is_encrypted():
|
||||||
storage.read(password)
|
password = getpass.getpass('Password:', stream=None)
|
||||||
|
storage.decrypt(password)
|
||||||
|
|
||||||
self.done = 0
|
self.done = 0
|
||||||
self.last_balance = ""
|
self.last_balance = ""
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ class ElectrumGui:
|
|||||||
if not storage.file_exists:
|
if not storage.file_exists:
|
||||||
print "Wallet not found. try 'electrum create'"
|
print "Wallet not found. try 'electrum create'"
|
||||||
exit()
|
exit()
|
||||||
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
|
if storage.is_encrypted():
|
||||||
storage.read(password)
|
password = getpass.getpass('Password:', stream=None)
|
||||||
|
storage.decrypt(password)
|
||||||
self.wallet = Wallet(storage)
|
self.wallet = Wallet(storage)
|
||||||
self.wallet.start_threads(self.network)
|
self.wallet.start_threads(self.network)
|
||||||
self.contacts = StoreDict(self.config, 'contacts')
|
self.contacts = StoreDict(self.config, 'contacts')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from version import ELECTRUM_VERSION
|
from version import ELECTRUM_VERSION
|
||||||
from util import format_satoshis, print_msg, print_error, set_verbosity
|
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 coinchooser import COIN_CHOOSERS
|
||||||
from network import Network, pick_random_server
|
from network import Network, pick_random_server
|
||||||
from interface import Connection, Interface
|
from interface import Connection, Interface
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
import os
|
import os
|
||||||
import bitcoin
|
import bitcoin
|
||||||
import keystore
|
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 i18n import _
|
||||||
from plugins import run_hook
|
from plugins import run_hook
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ from version import ELECTRUM_VERSION
|
|||||||
from network import Network
|
from network import Network
|
||||||
from util import json_decode, DaemonThread
|
from util import json_decode, DaemonThread
|
||||||
from util import print_msg, print_error, print_stderr, UserCancelled
|
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 commands import known_commands, Commands
|
||||||
from simple_config import SimpleConfig
|
from simple_config import SimpleConfig
|
||||||
from plugins import run_hook
|
from plugins import run_hook
|
||||||
@@ -203,15 +204,13 @@ class Daemon(DaemonThread):
|
|||||||
wallet = self.wallets[path]
|
wallet = self.wallets[path]
|
||||||
return wallet
|
return wallet
|
||||||
storage = WalletStorage(path)
|
storage = WalletStorage(path)
|
||||||
if not storage.file_exists:
|
if not storage.file_exists():
|
||||||
return
|
return
|
||||||
if storage.is_encrypted():
|
if storage.is_encrypted():
|
||||||
password = password_getter()
|
password = password_getter()
|
||||||
if not password:
|
if not password:
|
||||||
raise UserCancelled()
|
raise UserCancelled()
|
||||||
else:
|
storage.decrypt(password)
|
||||||
password = None
|
|
||||||
storage.read(password)
|
|
||||||
if storage.requires_split():
|
if storage.requires_split():
|
||||||
return
|
return
|
||||||
if storage.requires_upgrade():
|
if storage.requires_upgrade():
|
||||||
|
|||||||
@@ -64,52 +64,19 @@ def multisig_type(wallet_type):
|
|||||||
class WalletStorage(PrintError):
|
class WalletStorage(PrintError):
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
|
self.print_error("wallet path", path)
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
self.data = {}
|
self.data = {}
|
||||||
self.path = path
|
self.path = path
|
||||||
self.file_exists = self.path and os.path.exists(self.path)
|
|
||||||
self.modified = False
|
self.modified = False
|
||||||
self.pubkey = None
|
self.pubkey = None
|
||||||
|
if self.file_exists():
|
||||||
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:
|
|
||||||
with open(self.path, "r") as f:
|
with open(self.path, "r") as f:
|
||||||
s = f.read(8)
|
self.raw = f.read()
|
||||||
except IOError:
|
if not self.is_encrypted():
|
||||||
return
|
self.load_data(self.raw)
|
||||||
try:
|
|
||||||
return base64.b64decode(s).startswith('BIE1')
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def read(self, password):
|
def load_data(self, s):
|
||||||
"""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)
|
|
||||||
try:
|
try:
|
||||||
self.data = json.loads(s)
|
self.data = json.loads(s)
|
||||||
except:
|
except:
|
||||||
@@ -119,6 +86,33 @@ class WalletStorage(PrintError):
|
|||||||
l = plugin_loaders.get(t)
|
l = plugin_loaders.get(t)
|
||||||
if l: l()
|
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):
|
def get(self, key, default=None):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
v = self.data.get(key)
|
v = self.data.get(key)
|
||||||
@@ -150,7 +144,6 @@ class WalletStorage(PrintError):
|
|||||||
self.put('seed_version', FINAL_SEED_VERSION)
|
self.put('seed_version', FINAL_SEED_VERSION)
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self._write()
|
self._write()
|
||||||
self.file_exists = True
|
|
||||||
|
|
||||||
def _write(self):
|
def _write(self):
|
||||||
if threading.currentThread().isDaemon():
|
if threading.currentThread().isDaemon():
|
||||||
@@ -230,7 +223,7 @@ class WalletStorage(PrintError):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def requires_upgrade(self):
|
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):
|
def upgrade(self):
|
||||||
self.convert_imported()
|
self.convert_imported()
|
||||||
@@ -371,7 +364,7 @@ class WalletStorage(PrintError):
|
|||||||
action = run_hook('get_action', self)
|
action = run_hook('get_action', self)
|
||||||
if action:
|
if action:
|
||||||
return action
|
return action
|
||||||
if not self.file_exists:
|
if not self.file_exists():
|
||||||
return 'new'
|
return 'new'
|
||||||
|
|
||||||
def get_seed_version(self):
|
def get_seed_version(self):
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ from mnemonic import Mnemonic
|
|||||||
|
|
||||||
import paymentrequest
|
import paymentrequest
|
||||||
|
|
||||||
from storage import WalletStorage
|
|
||||||
|
|
||||||
TX_STATUS = [
|
TX_STATUS = [
|
||||||
_('Replaceable'),
|
_('Replaceable'),
|
||||||
|
|||||||
Reference in New Issue
Block a user